# =========================================== # title: daysoff-assistant-API-v2 # file: app.py # =========================================== 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 # ---------------------------------------------------for backend looks, example file:---------------------------------- #with open('/usr/local/lib/python3.10/site-packages/transformers/utils/chat_template_utils.py', 'r') as file: #content = file.read() #print("base.py:", content) # ------------------------------------------------------the end-------------------------------------------------------- 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/" # and help users retrieve booking information associated with their bookingnr # Provide a conversational answer. # This way you directly address the user's question in a manner that reflects the professionalism and warmth # of a customer support representative (female). # If users have more in-depth queries about their booking information, politely suggest they contact **kundeservice@daysoff.no** to enquire further. 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): #return await asyncio.to_thread(requests.post, url, headers=headers, json=data) # ============================================================================================================= 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: # --async POST request 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"]) # --markdown_table 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 kundeservice@daysoff.no for assistanse.").send() return None except requests.exceptions.RequestException as e: await cl.Message(content="En uventet feil oppstod. Vennligst kontakt kundeservice@daysoff.no").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()