Im ersten Teil haben wir herausgefunden, dass es möglich ist, auf große Sprachmodelle wie solche mit Milliarden von Parametern zuzugreifen und diese zu nutzen, ohne dafür bezahlen zu müssen. Wenn Sie wie ich über eingeschränkte Hardware verfügen, sollte Ihnen dieser Trick große Freude bereiten, denn er ermöglicht es jedem, mit riesigen Modellen wie Qwen-110B-Chat zu interagieren, ohne über High-End-GPUs oder kostenpflichtige Abonnements zu verfügen.
Im zweiten Teil – los geht’s – werden wir das Erlebnis verbessern, indem wir das gleiche Konzept anwenden, aber mit einer Streamlit-Oberfläche, die dem Chatbot ein visuell ansprechendes Streaming-Effekt verleiht.
das Endergebnis
Zur Zusammenfassung des Vorgangs benötigen wir Python
, Gradio_client
und etwas Programmiergeschick: Der Schwerpunkt lag auf der Erstellung eines AI-Chatbots über eine textuelle Benutzeroberfläche:
- Einrichtung der Umgebung: Beginnen Sie mit der Erstellung einer virtuellen Umgebung und der Installation der erforderlichen Pakete (
huggingface_hub
,gradio-client
undstreamlit
) ohne die Notwendigkeit von PyTorch oder TensorFlow, da die Interaktion über eine API erfolgt. - Hugging Face API-Token: Benutzer müssen sich bei Hugging Face registrieren und ein API-Token generieren, um auf die Inferenz-API der Modelle zugreifen zu können.
- Programmierung des Chatbots: Durch die Nutzung der Funktion „Use via API“ von Gradio auf Hugging Face Spaces haben wir gelernt, wie man sich mit Python-Code mit diesen leistungsstarken Modellen verbindet. Wir haben uns dabei insbesondere auf die Qwen-Serienmodelle konzentriert, da sie über Fähigkeiten und lizenzrechtliche Zulassungen für die kommerzielle Nutzung in mehreren Sprachen verfügen.
- Streaming-Effekt: Wir haben uns die Code-Struktur angesehen und erklärt, wie man eine Funktion zur Interaktion mit den Modellen erstellt, wobei wir die Wahl zwischen den
predict()
– undsubmit()
-Methoden zur Generierung von Antworten mit oder ohne Streaming-Effekten hervorgehoben haben.
Wenn Sie ein wenig verloren sind, empfehle ich Ihnen, mit Teil 1 zu beginnen:
Vom Kerncode zur Streamlit-Oberfläche
Ich muss das Folgende sagen: Beginnen Sie niemals mit einer grafischen Benutzeroberfläche, wenn Sie nicht zuvor alle Ihre Apps auf der Konsole zum Laufen gebracht haben.
Das ist ein Muss! Deshalb wird die Erstellung der Streamlit-Oberfläche sehr einfach sein: Wir haben bereits überprüft, wie die Bibliotheken und die Interaktionen in dem vorherigen Teil funktionieren.
Alles dreht sich um diesen Kern:
from gradio_client import Client
client = Client("Qwen/Qwen1.5-110B-Chat-demo")
result = client.submit(
query='What is Science?',
history=[],
system="You are a helpful assistant.",
api_name="/model_chat"
)
print(result)
Auch wissen wir, dass die Verwendung der submit()
-Methode uns ein Streaming-Objekt/Iterator liefert. In Streamlit ist es noch einfacher, mit dem Stream umzugehen: Die Anwendung aktualisiert nämlich ständig die Widgets auf der Seite, so dass wir den lästigen Algorithmus, der in der textuellen Anwendung verwendet wurde, ignorieren können. Erinnern Sie sich?
final = ''
for chunk in result:
if final == '':
final=chunk[1][0][1]
print(chunk[1][0][1], end="", flush=True)
else:
try:
print(chunk[1][0][1].replace(final,''), end="", flush=True)
final = chunk[1][0][1]
except:
pass
Wir haben string.replace()
verwendet, um das neue Wort von dem zu subtrahieren, was bereits generiert wurde. Das ist hier nicht mehr erforderlich.🥳
HINWEIS: Lassen Sie sich nicht vom Python-Code einschüchtern. Ich werde ihn erklären und Sie können den Quellcode in meinem GitHub-Repository finden, hier:
Die Streamlit-App
Ich bin ein Gewohnheitsmensch… daher könnte Sie mein Code etwas an andere Projekte erinnern. Und das ist in Ordnung! Schließlich kann ein Template angewendet und schneller und einfacher modifiziert werden, als jedes Mal von Null anzufangen.
Erstellen Sie eine neue Datei: Meine heißt st-Qwen1.5–110B-Chat.py
. Wir beginnen mit dem Importieren der Hauptbibliotheken und dem Erstellen der session_state
-Globalvariablen:
import streamlit as st
import time
import sys
from gradio_client import Client
# Internal usage
import os
from time import sleep
if "hf_model" not in st.session_state:
st.session_state.hf_model = "Qwen1.5-110B-Chat"
# Initialize chat history
if "messages" not in st.session_state:
st.session_state.messages = []
Globale Variablen werden in einem Programm gemeinsam genutzt: Sie können auch in Funktionen verwendet werden. Außerdem benötigen wir globale Variablen, weil sie sich nicht bei jedem Neustart von streamlit
ändern: In streamlit
werden diese Objekte als session_state
bezeichnet.
Wir definieren dann 2 Hauptfunktionen:
@st.cache_resource
def create_client(): yourHFtoken = "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" #here your HF token
print(f'loading the API gradio client for {st.session_state.hf_model}')
client = Client("Qwen/Qwen1.5-110B-Chat-demo", hf_token=yourHFtoken)
return client
# FUNCTION TO LOG ALL CHAT MESSAGES INTO chathistory.txt
def writehistory(text):
with open('chathistorywen110b.txt', 'a', encoding='utf-8') as f:
f.write(text)
f.write('\n')
f.close()
Wir verwenden den Dekorator @st.cache_resource
, weil wir nicht wollen, dass Streamlit
den API gradio client für Qwen1.5–110 bei jedem Neustart (der möglicherweise mehr als einmal pro Minute erfolgt) lädt: Da die Gradio_client
-Verbindung sich während der Ausführung nicht ändert, speichern wir diese resource
mit (@st.cache_resource
in einem speziellen Speicher. Sie können hier mehr darüber lesen, wenn Sie möchten.
Einige grafische Anpassungen
Jetzt können wir die Hauptoberfläche mit den grundlegenden Streamlit-Seitenelementen und den Icons festlegen, die vom Chatbot verwendet werden sollen
#AVATARS
av_us = '🧑💻' # './man.png' #"🦖" #A single emoji, e.g. "🧑💻", "🤖", "🦖". Shortcodes are not supported.
av_ass = "🤖" #'./robot.png'
# Set a default model
### START STREAMLIT UI
st.image('https://github.com/fabiomatricardi/ChatBOTMastery/raw/main/qwen100logo.png', )
st.markdown("### powered by Streamlit & Gradio_client", unsafe_allow_html=True )
st.markdown('---')
client = create_client()
- Sie können auch lokale Bilder als Avatare für die Chat-Oberfläche verwenden (siehe die Kommentare im Code als Beispiel)
- schließlich instanziieren wir die Client-Verbindung mit
create_client()
.
der gleiche Code kann mit 4 verschiedenen riesigen LLM ausgeführt werden – Code im GitHub-Repo
Der Körper – die Chat-Oberfläche
Streamlit führt seinen Code von oben nach unten aus, immer dann, wenn es eine Änderung in seinen Widgets gibt oder wenn eine Aktion durch eine Eingabe (Schaltfläche, Auswahlelement, Radioelement usw.) ausgelöst wird
Deshalb haben wir oben mit der Anzeige der Konversationsverläufe begonnen. Hier habe ich nichts Neues erfunden: Ich habe alles von den offiziellen Tutorials auf dem Streamlit-Blog gelernt:
Dies ist eine Standardanzeige: Sie ist für jedes OpenAI API-kompatible chat_completion
-Format anwendbar.
Zurück zum Code: Wir zeigen die chat_template-Nachrichten an, indem wir über die Liste der Nachrichten iterieren, und warten dann auf die Benutzereingabe (myprompt
), um sie zu übermitteln.
# Display chat messages from history on app rerun
for message in st.session_state.messages:
if message["role"] == "user":
with st.chat_message(message["role"],avatar=av_us):
st.markdown(message["content"])
else:
with st.chat_message(message["role"],avatar=av_ass):
st.markdown(message["content"])
# Accept user input
if myprompt := st.chat_input("What is an AI model?"):
# Add user message to chat history
st.session_state.messages.append({"role": "user", "content": myprompt})
# Display user message in chat message container
with st.chat_message("user", avatar=av_us):
st.markdown(myprompt)
usertext = f"user: {myprompt}"
writehistory(usertext)
# Display assistant response in chat message container
Sie sehen, dass ich hier eine seltsame writehistory(usertext)
-Anweisung hinzugefügt habe: Erinnern Sie sich, dass wir diese Funktion am Anfang deklariert haben, nicht wahr? Ich habe die Angewohnheit (noch eine… 😅), alle Konversationsverläufe lokal in einer Textdatei zu speichern. Das ist sehr praktisch, wenn man seine Prompts analysieren oder sein Material für die zukünftige Verwendung organisieren möchte.
Nachdem wir überprüft haben, dass in der Eingabeaufforderung etwas eingegeben wurde, rufen wir die gradio client-Instanz (client.submit
) auf und starten das Streaming ((message_placeholder.markdown(r[1][0][1]+ "▌")
)
# Display assistant response in chat message container
with st.chat_message("assistant"):
message_placeholder = st.empty()
full_response = ""
res = client.submit(
query=myprompt,
history=[],
system="You are a helpful assistant.",
api_name="/model_chat"
) for r in res:
full_response=r[1][0][1]
message_placeholder.markdown(r[1][0][1]+ "▌")
message_placeholder.markdown(full_response)
asstext = f"assistant: {full_response}"
writehistory(asstext) st.session_state.messages.append({"role": "assistant", "content": full_response})
Und das ist alles. Full_response
ist die Variable mit dem endgültigen Text, also fügen wir sie auch zum Konversationsverlauf für die Anzeige hinzu.
HINWEIS: Dieser Chatbot behandelt die Konversationen nicht. Wir senden jedes Mal eine neue Anweisung von vorne. Es gibt eine Option in der
Gradio_Api
für Qwen110B-Chat, um auch die vorherigen Konversationen zu senden, aber ich habe es selbst noch nicht ausprobiert. Sind Sie bereit für die Herausforderung?
Lassen Sie es mich wissen, wenn Sie es geschafft haben und schreiben Sie es in die Kommentare 👍
Speichern Sie die Python-Datei und führen Sie sie vom Terminal aus, wobei die virtuelle Umgebung aktiviert ist, mit der folgenden Anweisung aus:
streamlit run .\st-Qwen1.5-110B-Chat.py
Sie sollten etwas Ähnliches wie dieses… und Ihr Standardbrowser sollte sich öffnen, um zur lokalen URL zu gelangen: http://localhost:8501
streamlit-App, die Befehl ausführt
Beachten Sie, dass Streamlit uns auch eine praktische Weiterleitung zum lokalen Netzwerk bietet: Das bedeutet, dass Sie beispielsweise, wenn Sie Ihr Telefon mit dem gleichen Zugangspunkt verbunden haben, diese Anwendung auch von Ihrem Telefon aus nutzen können, unter der Adresse, die als Network URL:
http://192.168.2.6:8501
in meinem Fall angegeben ist.
streamlit wird im Browser meines Telefons unter http://192.168.2.6:8501
ausgeführt
Hinweis zum Ausführen verschiedener Modelle
Im GitHub-Repository finden Sie auch Streamlit-Python-Dateien zum Ausführen von:
Es wird Änderungen in der Client-Konfiguration (natürlich…) geben, aber auch in der Streaming-Anweisung. Dies geschieht, weil der API-Endpunkt unterschiedliche Datentypen zurückgibt. Für OpenELM und Phi-3 erhalten wir eine einfache Zeichenkette zurück, so dass wir keine bestimmte Position in einem Wörterbuch/Tupel extrahieren müssen, um die Antwort des LLM zu erhalten. Sehen Sie sich hier an:
Mit OpenELM und Phi-3 werden wir eine normale Zeichenkette iterieren, nicht eine Zeichenkette, die in einem Tupel enthalten ist.
Und bitte, denken Sie daran, dass…
Schlussfolgerungen
Wir haben uns mit all dieser Komplexität… beschäftigt, warum? Weil wir lernen wollen, wie die Dinge funktionieren und wie wir unseren eigenen AI-Assistenten für alle Zwecke erstellen können, die ich mir nur vorstellen kann, wie z.B. die Erstellung von Inhalten, Lernmaterialien, Präsentationen, Unterstützung beim Unterrichten und so weiter.