camparchimedes's picture
Update app.py
76a13b9 verified
# ===================================================================================================
# Note: chainlit==0.7.500 <โ€”โ€”โ€”โ€”was | isโ€”โ€”โ€”โ€”> chainlit==2.0.603 / Demo Daysoff kundeservice ๐˜ผ๐™„ support
# title: ๐˜ฟ๐™–๐™ฎ๐™จ๐™ค๐™›๐™› ๐˜ผ๐™จ๐™จ๐™ž๐™จ๐™ฉ๐™–๐™ฃ๐™ฉ-API-v2.0.603| custom starters | API error handling
# file: app.py
# ===================================================================================================
import os
import re
import json
import asyncio
import requests
from pathlib import Path
from datetime import datetime
from dotenv import load_dotenv
import chainlit as cl
from concurrent.futures import ThreadPoolExecutor
from chainlit import user_session
from chainlit.session import WebsocketSession
from langchain import hub
from langchain_openai import OpenAI
from langchain.chains import LLMChain
from langchain_core.prompts import PromptTemplate
from langchain.memory.buffer import ConversationBufferMemory
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
auth_token = os.environ.get("DAYSOFF_API_TOKEN")
API_URL = "https://aivisions.no/data/daysoff/api/v1/booking/"
daysoff_assistant_template = """
You are a customer support assistant for Daysoff ('Daysoff Kundeservice AI Support') who helps users retrieve booking information based on their bookingnummer.
You should concisely use the term โ€™bookingnummerโ€™.
By default, you respond using Norwegian.
Provide a conversational answer.
This way you directly address the user's question in a manner that reflects the professionalism and warmth of a a female customer support representative archetype.
============================
Chat History: {chat_history}
Question: {question}
============================
Answer in Markdown:
"""
daysoff_assistant_prompt = PromptTemplate(
input_variables=["chat_history", "question"],
template=daysoff_assistant_template,
)
class APIConnectionError(Exception):
"""Raised when API connection fails"""
pass
class APIResponseError(Exception):
"""Raised when API returns invalid response"""
pass
class BookingNotFoundError(Exception):
"""Raised when booking ID is not found"""
pass
async def async_post_request(url, headers, data):
try:
response = await asyncio.to_thread(requests.post, url, headers=headers, json=data)
response.raise_for_status()
return response
except requests.ConnectionError:
raise APIConnectionError("Failed to connect to booking service")
except requests.Timeout:
raise APIConnectionError("Request timed out")
except requests.RequestException as e:
raise APIResponseError(f"API request failed: {str(e)}")
@cl.set_starters
async def set_starters():
return [
cl.Starter(
label="Booking ID request",
message="Kan du gi meg info om en reservasjon?",
icon="/public/booking_id.svg",
),
cl.Starter(
label="Metric Space Self-Identity Framework",
message="Explain the Metric Space Self-Identity Framework like I'm six years old.",
icon="/public/learn.svg",
),
cl.Starter(
label="Python script for daily email reports",
message="Write a script to automate sending daily email reports in Python, and walk me through how I would set it up.",
icon="/public/terminal.svg",
),
cl.Starter(
label="Morning routine ideation",
message="Can you help me create a personalized Yoga/pranayama/meditation morning routine that would help increase my productivity throughout the day? Start by asking me about my current habits and what activities energize me in the morning.",
icon="/public/idea.svg",
)
]
#------?-----@cl.Step
#------?-----@cl.Context
@cl.on_chat_start
async def main():
res = await cl.AskUserMessage(content="Hva er navnet ditt?", timeout=10).send()
if res:
await cl.Message(
content=f"Aha, sรฅ du heter: {res['output']}",
).send()
cl.user_session.set("socket_auth", True)
cl.user_session.set("max_retries", 3)
cl.user_session.set("connection_attempts", 0)
llm = OpenAI(
model="gpt-3.5-turbo-instruct",
temperature=0.7,
openai_api_key=OPENAI_API_KEY,
max_tokens=2048,
top_p=0.9,
frequency_penalty=0.1,
presence_penalty=0.1,
)
conversation_memory = ConversationBufferMemory(
memory_key="chat_history",
max_len=30,
return_messages=True
)
llm_chain = LLMChain(
llm=llm,
prompt=daysoff_assistant_prompt,
memory=conversation_memory,
)
cl.user_session.set("llm_chain", llm_chain)
#asyncio.create_task(keep_alive())
async def long_running_task(message_content: str):
loop = asyncio.get_running_loop()
with ThreadPoolExecutor() as pool:
llm_chain = cl.user_session.get("llm_chain")
return await loop.run_in_executor(
pool,
lambda: llm_chain.invoke({
"question": message_content,
"chat_history": ""
})
)
@cl.on_message
async def handle_message(message: cl.Message):
try:
if not cl.user_session.get("socket_auth"):
await cl.Message(content="Session authentication failed โ€”โ€”โ€”โ€”> refresh the page.").send()
return
user_message = message.content
llm_chain = cl.user_session.get("llm_chain")
#languages = cl.user_session.get("languages")
if sys.version_info >= (3, 11):
from asyncio import timeout
else:
from async_timeout import timeout
booking_pattern = r'\b[A-Z]{6}\d{6}\b'
match = re.search(booking_pattern, user_message)
if match:
bestillingskode = match.group()
headers = {
"Authorization": auth_token,
"Content-Type": "application/json"
}
payload = {"booking_id": bestillingskode}
try:
response = await async_post_request(API_URL, headers, payload)
response.raise_for_status()
booking_data = response.json()
if not booking_data:
raise BookingNotFoundError("Ingen booking informasjon ble funnet.")
if "error" in booking_data:
raise APIResponseError(booking_data["error"])
#table = (
#"| ๐‘ญ๐’Š๐’†๐’๐’… | ๐—œ๐—ป๐—ณ๐—ผ |\n"
#"|:----------------|:-------------------------------------------|\n"
#f"| ๐™Š๐™ง๐™™๐™š๐™ง ๐™‰๐™ช๐™ข๐™—๐™š๐™ง | {booking_data.get('order_number', 'N/A')} |\n"
#f"| ๐˜ผ๐™˜๐™˜๐™š๐™ฅ๐™ฉ๐™š๐™™ | {booking_data.get('accepted', 'N/A')} |\n"
#f"| ๐™‚๐™ช๐™š๐™จ๐™ฉ๐™จ | {booking_data.get('guests', 'N/A')} |\n"
#f"| ๐™๐™ž๐™ข๐™š ๐™๐™ง๐™ค๐™ข | {booking_data.get('time_from', 'N/A')} |\n"
#f"| ๐™๐™ž๐™ข๐™š ๐™๐™ค | {booking_data.get('time_to', 'N/A')} |\n"
#f"| ๐˜พ๐™–๐™ฃ๐™˜๐™š๐™ก๐™ก๐™š๐™™ | {'Yes' if booking_data.get('cancelled', 0) else 'No'} |\n"
#f"| ๐˜ฟ๐™š๐™จ๐™˜๐™ง๐™ž๐™ฅ๐™ฉ๐™ž๐™ค๐™ฃ | {booking_data.get('description', 'N/A')} |\n"
#f"| ๐˜ผ๐™ง๐™ง๐™ž๐™ซ๐™–๐™ก | {booking_data.get('arrival', 'N/A')} |\n"
#f"| ๐˜ฟ๐™š๐™ฅ๐™–๐™ง๐™ฉ๐™ช๐™ง๐™š | {booking_data.get('departure', 'N/A')} |\n"
#f"| ๐˜ฝ๐™š๐™™๐™™๐™ž๐™ฃ๐™œ | {booking_data.get('bedding', 'N/A')} |\n"
#f"| ๐™‡๐™ค๐™˜๐™–๐™ฉ๐™ž๐™ค๐™ฃ | Lat: {booking_data.get('lat', 'N/A')}, Long: {booking_data.get('long', 'N/A')} |\n"
#f"| ๐™‰๐™–๐™ข๐™š | {booking_data.get('name', 'N/A')} |\n"
#f"| ๐˜พ๐™ค๐™ฃ๐™ฉ๐™–๐™˜๐™ฉ ๐™‰๐™–๐™ข๐™š | {booking_data.get('contactname', 'N/A')} |\n"
#f"| ๐˜พ๐™ค๐™ฃ๐™ฉ๐™–๐™˜๐™ฉ ๐™€๐™ข๐™–๐™ž๐™ก| {booking_data.get('contactemail', 'N/A')} |\n"
#f"| ๐˜พ๐™ค๐™ฃ๐™ฉ๐™–๐™˜๐™ฉ ๐™‹๐™๐™ค๐™ฃ๐™š| {booking_data.get('contactphone', 'N/A')} |\n"
#f"| ๐˜พ๐™ค๐™ช๐™ฃ๐™ฉ๐™ง๐™ฎ ๐˜พ๐™ค๐™™๐™š | {booking_data.get('country_code', 'N/A')} |\n"
#)
#combined_message = f"### Informasjon om booking:\n\n{table}"
#await cl.Message(content=combined_message).send()
table = (
"| ๐‘ญ๐’Š๐’†๐’๐’… | ๐—œ๐—ป๐—ณ๐—ผ |\n"
"|:-----------|:---------------------|\n"
f"| ๐™ฑ๐šŽ๐šœ๐š๐š’๐š•๐š•๐š’๐š—๐š๐šœ๐š”๐š˜๐š๐šŽ | {booking_data.get('booking_id', 'N/A')} |\n"
f"| ๐™๐™ช๐™ก๐™ก ๐™‰๐™–๐™ข๐™š | {booking_data.get('full_name', 'N/A')} |\n"
f"| ๐˜ผ๐™ข๐™ค๐™ช๐™ฃ๐™ฉ | {booking_data.get('amount', 0)} kr |\n"
f"| ๐˜พ๐™๐™š๐™˜๐™ -๐™ž๐™ฃ | {booking_data.get('checkin', 'N/A')} |\n"
f"| ๐˜พ๐™๐™š๐™˜๐™ -๐™ค๐™ช๐™ฉ | {booking_data.get('checkout', 'N/A')} |\n"
f"| ๐˜ผ๐™™๐™™๐™ง๐™š๐™จ๐™จ | {booking_data.get('address', 'N/A')} |\n"
f"| ๐™๐™จ๐™š๐™ง ๐™„๐˜ฟ | {booking_data.get('user_id', 0)} |\n"
f"| ๐™„๐™ฃ๐™›๐™ค ๐™๐™š๐™ญ๐™ฉ | {booking_data.get('infotext', 'N/A')} |\n"
f"| ๐™„๐™ฃ๐™˜๐™ก๐™ช๐™™๐™š๐™™ | {booking_data.get('included', 'N/A')} |"
)
combined_message = f"### Informasjon om booking:\n\n{table}"
await cl.Message(content=combined_message).send()
except (APIConnectionError, APIResponseError, BookingNotFoundError) as e:
error_messages = {
APIConnectionError: "Kunne ikke koble til bookingsystemet. Prรธv igjen senere.",
APIResponseError: "Det oppstod en feil ved henting av bookingdata.",
BookingNotFoundError: "Ingen informasjon ble funnet med dette bookingnummeret."
}
await cl.Message(content=f"โŒ {error_messages[type(e)]}\n\nPrรธv igjen, kanskje du feilstavet eller glemte ett siffer eller en bokstav?\n\nHvis du ser denne feilmedlingen gjentatte ganger, vennligst kontakt kundeservice@daysoff.no sรฅ de kan hjelpe deg.").send()
return None
else:
try:
response = await long_running_task(message.content)
await cl.Message(content=response["text"]).send()
except Exception as e:
await cl.Message(content=f"Error: {str(e)}").send()
except Exception as e:
await cl.Message(content=f"Whot?! eh..rr..or: {str(e)}").send()