|
|
|
|
|
|
|
|
|
|
|
import json |
|
import asyncio |
|
import os |
|
import re |
|
import requests |
|
from dotenv import load_dotenv |
|
import chainlit as cl |
|
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โ. Maintain a conversational and professional tone, **reflecting the warmth of a female customer support |
|
representative archetype.** By default, you answer in **Norwegian**. |
|
Chat History: {chat_history} |
|
Question: {question} |
|
Answer: |
|
""" |
|
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.on_chat_start |
|
def setup_multiple_chains(): |
|
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) |
|
|
|
@cl.on_message |
|
async def handle_message(message: cl.Message): |
|
user_message = message.content |
|
llm_chain = cl.user_session.get("llm_chain") |
|
|
|
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("No booking data returned") |
|
|
|
if "error" in booking_data: |
|
raise APIResponseError(booking_data["error"]) |
|
|
|
|
|
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 booking funnet med denne koden." |
|
} |
|
await cl.Message(content=f"โ {error_messages[type(e)]}\n\nPrรธv igjen, kanskje du feilstavet eller glemte ett siffer?\n\nHvis du ser denne feilmedlingen gjentatte ganger, foreslรฅr jeg at du kontakt [email protected] for assistanse.").send() |
|
return None |
|
except requests.exceptions.RequestException as e: |
|
await cl.Message(content="En uventet feil oppstod. Vennligst kontakt [email protected]").send() |
|
return None |
|
|
|
else: |
|
try: |
|
response = await llm_chain.ainvoke({ |
|
"question": user_message, |
|
"chat_history": "" |
|
}, callbacks=[cl.AsyncLangchainCallbackHandler()]) |
|
await cl.Message(content=response["text"]).send() |
|
except Exception as e: |
|
await cl.Message(content=f"Error: {str(e)}").send() |
|
|