# ============================================================================= # 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 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 ------------------ try: # Versuche zuerst aus Umgebungsvariablen zu laden HF_TOKEN_MEMORY = os.getenv("HF_TOKEN_MEMORY", "") # Wenn nicht vorhanden, versuche aus st.secrets zu laden 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)}") except Exception as e: logger.warning(f"Fehler beim Laden des Tokens: {str(e)}") HF_TOKEN_MEMORY = "" # Debug-Ausgabe (nur während der Entwicklung, später entfernen) if HF_TOKEN_MEMORY: # Nicht den vollständigen Token loggen! 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!") st.warning("⚠️ Hugging Face Token fehlt. 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: st.warning("⚠️ API-Key benötigt") st.stop() openai.api_key = openai_api_key # ------------------ Dataset Funktionen ------------------ # Korrekter Repository-Name DATASET_REPO = "AiCodeCraft/customer_memory" # Korrigiert von "AiCodeCarft" @st.cache_resource 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") # Einfaches lokales Dataset zurückgeben return Dataset.from_dict({"user_id": [], "query": [], "response": [], "timestamp": []}) try: # Mit Token versuchen 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)}") # Neues Dataset erstellen logger.info("Erstelle neues Dataset...") data = {"user_id": [], "query": [], "response": [], "timestamp": []} ds = Dataset.from_dict(data) try: # Dataset pushen ds.push_to_hub(DATASET_REPO, token=HF_TOKEN_MEMORY) logger.info("Neues Dataset erfolgreich erstellt und gepusht.") return ds except Exception as push_error: logger.error(f"Fehler beim Pushen des Datasets: {str(push_error)}") st.error("Konnte kein Dataset erstellen. Bitte überprüfe deine Berechtigungen.") # Lokales Dataset zurückgeben return ds # ------------------ AI Agent Klasse ------------------ class CustomerSupportAIAgent: def __init__(self): self.memory = load_memory_dataset() def handle_query(self, query, user_id): # Memory abrufen user_history = self.memory.filter(lambda x: x["user_id"] == user_id) # Kontext erstellen 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 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} ] ) # Antwort verarbeiten answer = response.choices[0].message.content # 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]) # Nur pushen, wenn Token vorhanden if HF_TOKEN_MEMORY: try: self.memory.push_to_hub(DATASET_REPO, token=HF_TOKEN_MEMORY) logger.info(f"Memory aktualisiert für User {user_id}") except Exception as e: logger.error(f"Fehler beim Aktualisieren des Datasets: {str(e)}") st.warning("Konnte Conversation History nicht speichern, aber Antwort ist verfügbar.") 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: st.sidebar.error("Bitte Customer ID eingeben") st.stop() # Chat-History if "messages" not in st.session_state: st.session_state.messages = [] # Nachrichten anzeigen for msg in st.session_state.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: st.error(f"Fehler beim Starten der App: {str(e)}") logger.error(f"Startup-Fehler: {str(e)}", exc_info=True)