Spaces:
Runtime error
Runtime error
# ============================================================================= | |
# DON'T STEAL THE FREE CODE OF DEVS! Use it for free an do not touch credits! | |
# If you steal this code, in the future you will pay for apps like this! | |
# A bit of respect goes a long way – all rights reserved under German law. | |
# Copyright Volkan Kücükbudak https://github.com/volkansah | |
# Repo URL: https://github.com/AiCodeCraft | |
# ============================================================================= | |
import streamlit as st | |
import os | |
import json | |
import datetime | |
import openai | |
from datetime import timedelta | |
import logging | |
from datasets import load_dataset, Dataset, concatenate_datasets | |
import sys | |
import schedule | |
import threading | |
import time | |
print("Python Version:", sys.version) | |
print("Importiere Module...") | |
# ------------------ Logging konfigurieren ------------------ | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | |
) | |
logger = logging.getLogger(__name__) | |
# ------------------ Initialisierung ------------------ | |
# Als globale Variable definieren | |
HF_TOKEN_MEMORY = "" | |
def main(): | |
global HF_TOKEN_MEMORY # Als global markieren | |
logger.info("App-Initialisierung gestartet...") | |
# ------------------ Hugging Face Token ------------------ | |
HF_TOKEN_MEMORY = os.getenv("HF_TOKEN_MEMORY", "") | |
if not HF_TOKEN_MEMORY: | |
try: | |
HF_TOKEN_MEMORY = st.secrets["HF_TOKEN_MEMORY"] | |
logger.info("Token aus Streamlit Secrets geladen") | |
except Exception as e: | |
logger.warning(f"Token nicht in Streamlit Secrets gefunden: {str(e)}") | |
if HF_TOKEN_MEMORY: | |
token_preview = HF_TOKEN_MEMORY[:4] + "..." if len(HF_TOKEN_MEMORY) > 4 else "Ungültig" | |
logger.info(f"HF Token gefunden. Startet mit: {token_preview}") | |
else: | |
logger.warning("Kein HF Token gefunden! Dataset-Funktionen werden nicht verfügbar sein.") | |
# ------------------ Streamlit UI ------------------ | |
st.title("AI Customer Support Agent with Memory 🛒") | |
st.caption("Chat with an assistant who remembers past interactions") | |
# OpenAI Key Eingabe | |
openai_api_key = st.text_input("Enter OpenAI API Key", type="password", key="openai_key") | |
if not openai_api_key: | |
logger.warning("API-Key benötigt") | |
st.stop() | |
openai.api_key = openai_api_key | |
# ------------------ Dataset Funktionen ------------------ | |
DATASET_REPO = "AiCodeCraft/customer_memory" # Repository existiert bereits | |
def load_memory_dataset(): | |
""" | |
Versucht, das Memory-Dataset vom HF Hub zu laden. | |
Falls nicht vorhanden, wird ein leeres Dataset erstellt und gepusht. | |
""" | |
if not HF_TOKEN_MEMORY: | |
logger.warning("Kein HF Token vorhanden, verwende lokales Dataset") | |
return Dataset.from_dict({"user_id": [], "query": [], "response": [], "timestamp": []}) | |
try: | |
logger.info(f"Versuche Dataset {DATASET_REPO} zu laden...") | |
ds = load_dataset(DATASET_REPO, split="train", token=HF_TOKEN_MEMORY) | |
logger.info(f"Dataset erfolgreich geladen mit {len(ds)} Einträgen.") | |
return ds | |
except Exception as e: | |
logger.warning(f"Fehler beim Laden des Datasets: {str(e)}") | |
logger.info("Erstelle neues Dataset...") | |
data = {"user_id": [], "query": [], "response": [], "timestamp": []} | |
ds = Dataset.from_dict(data) | |
try: | |
ds.push_to_hub(DATASET_REPO, token=HF_TOKEN_MEMORY) | |
logger.info("Neues Dataset erfolgreich erstellt und gepusht.") | |
except Exception as push_error: | |
logger.error(f"Fehler beim Pushen des Datasets: {str(push_error)}") | |
return ds | |
# ------------------ AI Agent Klasse ------------------ | |
class CustomerSupportAIAgent: | |
def __init__(self): | |
self.memory = load_memory_dataset() | |
self.schedule_push() | |
def schedule_push(self): | |
# Diese Funktion pusht das Dataset periodisch im Hintergrund | |
def push_memory(): | |
if HF_TOKEN_MEMORY: | |
try: | |
self.memory.push_to_hub(DATASET_REPO, token=HF_TOKEN_MEMORY) | |
logger.info("Memory erfolgreich aktualisiert (periodischer Push)") | |
except Exception as e: | |
logger.error(f"Fehler beim periodischen Aktualisieren des Datasets: {str(e)}") | |
schedule.every(10).minutes.do(push_memory) | |
threading.Thread(target=self.run_schedule, daemon=True).start() | |
def run_schedule(self): | |
while True: | |
schedule.run_pending() | |
time.sleep(1) | |
def handle_query(self, query, user_id): | |
# Memory abrufen | |
user_history = self.memory.filter(lambda x: x["user_id"] == user_id) | |
context = "Previous interactions:\n" + "\n".join( | |
[f"Q: {h['query']}\nA: {h['response']}" for h in user_history] | |
) if len(user_history) > 0 else "No previous interactions" | |
# API-Anfrage | |
try: | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[ | |
{"role": "system", "content": f"You are a support agent. Context:\n{context}"}, | |
{"role": "user", "content": query} | |
] | |
) | |
answer = response.choices[0].message.content | |
except Exception as e: | |
logger.error(f"Fehler bei OpenAI-API-Anfrage: {str(e)}") | |
answer = "Entschuldigung, ein Fehler ist aufgetreten." | |
# Memory aktualisieren mit Timestamp | |
current_time = datetime.datetime.now().isoformat() | |
new_entry = Dataset.from_dict({ | |
"user_id": [user_id], | |
"query": [query], | |
"response": [answer], | |
"timestamp": [current_time] | |
}) | |
self.memory = concatenate_datasets([self.memory, new_entry]) | |
logger.info(f"Memory lokal aktualisiert für User {user_id}") | |
# Der Push erfolgt periodisch im Hintergrund | |
return answer | |
# ------------------ App-Logik ------------------ | |
support_agent = CustomerSupportAIAgent() | |
# Customer ID Handling | |
customer_id = st.sidebar.text_input("Customer ID", key="cust_id") | |
if not customer_id: | |
logger.warning("Keine Customer ID eingegeben") | |
st.stop() | |
# Chat-History initialisieren | |
if "messages" not in st.session_state: | |
st.session_state.messages = [] | |
# Zeige nur die letzten 20 Nachrichten an | |
max_messages = 20 | |
displayed_messages = st.session_state.messages[-max_messages:] | |
for msg in displayed_messages: | |
st.chat_message(msg["role"]).write(msg["content"]) | |
# Eingabe verarbeiten | |
if prompt := st.chat_input("Your question"): | |
st.session_state.messages.append({"role": "user", "content": prompt}) | |
st.chat_message("user").write(prompt) | |
with st.spinner("Denke nach..."): | |
response = support_agent.handle_query(prompt, customer_id) | |
st.session_state.messages.append({"role": "assistant", "content": response}) | |
st.chat_message("assistant").write(response) | |
# ------------------ Hauptausführung ------------------ | |
if __name__ == "__main__": | |
try: | |
main() | |
except Exception as e: | |
logger.error(f"Startup-Fehler: {str(e)}", exc_info=True) | |