Spaces:
Runtime error
Runtime error
File size: 12,319 Bytes
a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 ea69cd5 a43dae1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# =============================================================================
# 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
# ------------------ Logging konfigurieren ------------------
logging.basicConfig(
level=logging.INFO, # Log-Level auf INFO setzen
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
logger.info("Starte App mit HF-Dataset Memory...")
# ------------------ Hugging Face Token laden ------------------
HF_TOKEN_MEMORY = os.getenv('HF_TOKEN_MEMORY', '').strip()
if HF_TOKEN_MEMORY:
logger.info("Hugging Face Token gefunden.")
else:
logger.warning("Kein Hugging Face Token gefunden. Falls benötigt, bitte setzen!")
# ------------------ Einstellungen für das Memory-Dataset ------------------
DATASET_REPO = "AiCodeCarft/customer_memory"
def load_memory_dataset():
"""
Versucht, das Memory-Dataset vom HF Hub zu laden.
Falls nicht vorhanden, wird ein leeres Dataset mit den Spalten
'user_id', 'query' und 'response' erstellt und gepusht.
"""
try:
ds = load_dataset(DATASET_REPO, split="train")
st.write("Dataset loaded from HF Hub.")
logger.info("Dataset erfolgreich vom HF Hub geladen.")
except Exception as e:
st.write("Dataset not found on HF Hub. Creating a new one...")
logger.info("Kein Dataset gefunden. Erstelle ein neues Dataset...")
data = {"user_id": [], "query": [], "response": []}
ds = Dataset.from_dict(data)
ds.push_to_hub(DATASET_REPO)
st.write("New dataset created and pushed to HF Hub.")
logger.info("Neues Dataset erfolgreich erstellt und gepusht.")
return ds
def add_to_memory(user_id, query, response):
"""
Fügt einen neuen Eintrag (Query und Antwort) zum Memory-Dataset hinzu
und pusht das aktualisierte Dataset an den HF Hub.
"""
ds = load_memory_dataset()
# Neuer Eintrag als kleines Dataset
new_entry = Dataset.from_dict({
"user_id": [user_id],
"query": [query],
"response": [response]
})
# Bestehendes Dataset mit dem neuen Eintrag zusammenführen
updated_ds = concatenate_datasets([ds, new_entry])
# Push updated dataset to HF Hub
updated_ds.push_to_hub(DATASET_REPO)
st.write("Memory updated.")
logger.info("Memory-Dataset erfolgreich aktualisiert.")
def get_memory(user_id):
"""
Filtert das Memory-Dataset nach der angegebenen Customer ID
und gibt alle Einträge (Query und Antwort) zurück.
"""
ds = load_memory_dataset()
filtered_ds = ds.filter(lambda x: x["user_id"] == user_id)
logger.info(f"Memory für User {user_id} abgerufen. {len(filtered_ds)} Einträge gefunden.")
return filtered_ds
# ------------------ OpenAI GPT-4 API-Anbindung ------------------
def generate_response(prompt):
"""
Sendet den Prompt an die OpenAI API und gibt die Antwort zurück.
"""
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a customer support AI for TechGadgets.com."},
{"role": "user", "content": prompt}
]
)
logger.info("Antwort von OpenAI erhalten.")
return response.choices[0].message.content
# ------------------ Streamlit App UI ------------------
st.title("AI Customer Support Agent with Memory 🛒")
st.caption("Chat with a customer support assistant who remembers your past interactions.")
# Eingabe des OpenAI API Keys
openai_api_key = st.text_input("Enter OpenAI API Key", type="password")
if openai_api_key:
os.environ['OPENAI_API_KEY'] = openai_api_key
openai.api_key = openai_api_key
logger.info("OpenAI API Key gesetzt.")
# ------------------ Klasse: CustomerSupportAIAgent ------------------
class CustomerSupportAIAgent:
def __init__(self):
# Wir nutzen hier die HF Dataset Funktionen als Memory-Speicher
self.client = openai # OpenAI Client
self.app_id = "customer-support"
def handle_query(self, query, user_id=None):
try:
# Hole relevante Erinnerungen aus dem HF Dataset
memories = get_memory(user_id)
context = "Relevant past information:\n"
# Falls Einträge vorhanden sind, baue den Kontext
if len(memories) > 0:
for entry in memories:
context += f"- Query: {entry['query']}\n Response: {entry['response']}\n"
logger.info("Kontext aus Memory-Dataset erstellt.")
# Kombiniere Kontext und aktuelle Anfrage
full_prompt = f"{context}\nCustomer: {query}\nSupport Agent:"
logger.info("Vollständiger Prompt für OpenAI erstellt.")
# Generiere Antwort mit OpenAI
answer = generate_response(full_prompt)
# Speicher die Interaktion im Memory-Dataset
add_to_memory(user_id, query, answer)
logger.info("Interaktion im Memory-Dataset gespeichert.")
return answer
except Exception as e:
logger.error(f"Fehler bei handle_query: {e}")
st.error(f"An error occurred while handling the query: {e}")
return "Sorry, I encountered an error. Please try again later."
def generate_synthetic_data(self, user_id: str) -> dict | None:
try:
today = datetime.datetime.now()
order_date = (today - timedelta(days=10)).strftime("%B %d, %Y")
expected_delivery = (today + timedelta(days=2)).strftime("%B %d, %Y")
# Prompt zur Generierung synthetischer Kundendaten für einen Lieferservice
prompt = f"""Generate a detailed customer profile and order history for a DeliverItExpress customer with ID {user_id}. Include:
1. Customer name and basic info (age, gender, and contact details)
2. A recent order of a gourmet meal (placed on {order_date} and delivered by {expected_delivery})
3. Order details including food items, total price, and order number
4. Customer's delivery address
5. 2-3 previous orders from the past year with different types of cuisines
6. 2-3 customer service interactions regarding delivery issues (e.g., late delivery, missing items)
7. Any preferences or patterns in their ordering behavior (e.g., favorite cuisines, peak ordering times)
Format the output as a JSON object."""
logger.info("Prompt for generating synthetic delivery service data created.")
response = self.client.ChatCompletion.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are a data generation AI that creates realistic customer profiles and order histories. Always respond with valid JSON."},
{"role": "user", "content": prompt}
]
)
logger.info("Antwort für synthetische Daten von OpenAI erhalten.")
customer_data = json.loads(response.choices[0].message.content)
# Optional: Speichere auch diese Daten im Memory-Dataset
for key, value in customer_data.items():
if isinstance(value, list):
for item in value:
add_to_memory(user_id, f"{key} item", json.dumps(item))
else:
add_to_memory(user_id, key, json.dumps(value))
logger.info("Synthetische Daten im Memory-Dataset gespeichert.")
return customer_data
except Exception as e:
logger.error(f"Fehler bei generate_synthetic_data: {e}")
st.error(f"Failed to generate synthetic data: {e}")
return None
# ------------------ Initialisierung des CustomerSupportAIAgent ------------------
support_agent = CustomerSupportAIAgent()
# ------------------ Sidebar: Customer ID und Optionen ------------------
st.sidebar.title("Enter your Customer ID:")
previous_customer_id = st.session_state.get("previous_customer_id", None)
customer_id = st.sidebar.text_input("Enter your Customer ID")
if customer_id != previous_customer_id:
st.session_state.messages = []
st.session_state.previous_customer_id = customer_id
st.session_state.customer_data = None
logger.info("Neue Customer ID erkannt – Chatverlauf und synthetische Daten zurückgesetzt.")
# Button: Synthetische Daten generieren
if st.sidebar.button("Generate Synthetic Data"):
if customer_id:
with st.spinner("Generating customer data..."):
st.session_state.customer_data = support_agent.generate_synthetic_data(customer_id)
if st.session_state.customer_data:
st.sidebar.success("Synthetic data generated successfully!")
logger.info("Synthetische Daten erfolgreich generiert.")
else:
st.sidebar.error("Failed to generate synthetic data.")
logger.error("Fehler beim Generieren synthetischer Daten.")
else:
st.sidebar.error("Please enter a customer ID first.")
logger.warning("Kein Customer ID eingegeben beim Versuch, synthetische Daten zu generieren.")
# Button: Customer Profile anzeigen
if st.sidebar.button("View Customer Profile"):
if st.session_state.customer_data:
st.sidebar.json(st.session_state.customer_data)
else:
st.sidebar.info("No customer data generated yet. Click 'Generate Synthetic Data' first.")
# Button: Memory-Info anzeigen
if st.sidebar.button("View Memory Info"):
if customer_id:
memories = get_memory(customer_id)
st.sidebar.write(f"Memory for customer **{customer_id}**:")
for mem in memories:
st.sidebar.write(f"**Query:** {mem['query']}\n**Response:** {mem['response']}\n---")
else:
st.sidebar.error("Please enter a customer ID.")
# ------------------ Chatverlauf initialisieren und anzeigen ------------------
if "messages" not in st.session_state:
st.session_state.messages = []
# Vorherige Nachrichten anzeigen
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# ------------------ Haupt-Chat: Benutzereingabe ------------------
query = st.chat_input("How can I assist you today?")
if query and customer_id:
# Benutzeranfrage zum Chatverlauf hinzufügen
st.session_state.messages.append({"role": "user", "content": query})
with st.chat_message("user"):
st.markdown(query)
logger.info("Benutzeranfrage hinzugefügt.")
# Generiere Antwort und zeige sie an
with st.spinner("Generating response..."):
answer = support_agent.handle_query(query, user_id=customer_id)
st.session_state.messages.append({"role": "assistant", "content": answer})
with st.chat_message("assistant"):
st.markdown(answer)
logger.info("Antwort des Assistenten hinzugefügt.")
elif query and not customer_id:
st.error("Please enter a customer ID to start the chat.")
logger.warning("Chat gestartet ohne Customer ID.")
else:
st.warning("Please enter your OpenAI API key to use the customer support agent.")
logger.info("Warte auf Eingabe des OpenAI API Keys.")
|