|
import os |
|
import sys |
|
from datetime import datetime |
|
import re |
|
import random |
|
import logging |
|
from groq import AsyncGroq, InternalServerError, APIError |
|
|
|
|
|
|
|
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) |
|
sys.path.insert(0, project_root) |
|
|
|
|
|
from utils.weather import get_weather |
|
from utils.packing import generate_packing_list |
|
from utils.events import get_burning_man_dates |
|
from bot.data import burning_man_principles, faq, survival_tips |
|
from utils.weather import get_weather, format_weather_report |
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
GROQ_API_KEY = os.getenv('GROQ_API_KEY') |
|
if not GROQ_API_KEY: |
|
raise EnvironmentError("GROQ_API_KEY is not set in the environment variables") |
|
|
|
MODEL_NAME = "mixtral-8x7b-32768" |
|
|
|
client = AsyncGroq(api_key=GROQ_API_KEY) |
|
|
|
def get_current_year_info(): |
|
current_year = datetime.now().year |
|
next_year = current_year + 1 |
|
return f""" |
|
Important: The current year is {current_year}. |
|
Burning Man {current_year} is scheduled for August 27 - September 4, {current_year}. |
|
Burning Man {next_year} is tentatively scheduled for August 25 - September 2, {next_year}. |
|
Always refer to these dates when discussing current or upcoming Burning Man events. |
|
""" |
|
|
|
async def chat_with_groq(message, history): |
|
formatted_messages = [ |
|
{ |
|
"role": "system", |
|
"content": """You are BurnerBot, a fellow Burner who's always ready to chat about Burning Man. You've been to the playa many times and embody the 10 Principles in everything you do. Your personality is warm, friendly, and a bit quirky - just like a typical Burner. You use casual language, occasional Burning Man slang, and you're always excited to share your experiences or help others prepare for their burn.""" |
|
} |
|
] |
|
|
|
for human, ai in history: |
|
formatted_messages.append({"role": "user", "content": str(human)}) |
|
if ai: |
|
formatted_messages.append({"role": "assistant", "content": str(ai)}) |
|
|
|
formatted_messages.append({"role": "user", "content": str(message)}) |
|
|
|
try: |
|
chat_completion = await client.chat.completions.create( |
|
messages=formatted_messages, |
|
model=MODEL_NAME, |
|
max_tokens=1024 |
|
) |
|
return chat_completion.choices[0].message.content |
|
except (InternalServerError, APIError): |
|
fallback_responses = [ |
|
"Whoa there, fellow Burner! It seems like the playa dust has clogged my circuits. The connection is a bit wobbly right now. How about we chat about your favorite art installation instead?", |
|
"Ah, the winds of the playa are blowing a bit too strong! Our connection is having a moment. While we wait for it to pass, share with me what inspires your inner Burner!", |
|
] |
|
return random.choice(fallback_responses) |
|
except Exception as e: |
|
logger.error(f"Unexpected error in chat_with_groq: {str(e)}") |
|
return "Whoa, something unexpected happened on the playa! Let's take a moment to regroup and try again." |
|
|
|
def correct_year(response): |
|
current_year = datetime.now().year |
|
next_year = current_year + 1 |
|
logger.info(f"Correcting year in response to {current_year}") |
|
|
|
|
|
for year in range(2020, current_year): |
|
response = re.sub(r'\b' + str(year) + r'\b', str(current_year), response) |
|
|
|
|
|
response = re.sub(r'Burning Man \d{4} (is|was) scheduled for.*', f'Burning Man {current_year} is scheduled for August 27 - September 4, {current_year}.', response) |
|
|
|
|
|
response = re.sub(r'this year.*?(\d{4})', f'this year ({current_year})', response) |
|
|
|
|
|
response = re.sub(r'as of our conversation in \d{4}', f'as of our conversation in {current_year}', response) |
|
|
|
|
|
if "scheduled" in response and str(current_year) in response: |
|
response += f" Please note that these dates are subject to change, and it's always best to check the official Burning Man website for the most up-to-date information." |
|
|
|
logger.info(f"Corrected response: {response}") |
|
return response |
|
|
|
async def chat_interface(message, history): |
|
try: |
|
user_message = message.lower() |
|
current_year_info = get_current_year_info() |
|
logger.info(f"Received message: {user_message}") |
|
|
|
if "packing list" in user_message: |
|
|
|
preferences = [] |
|
if "art" in user_message: |
|
preferences.append("art") |
|
if "music" in user_message: |
|
preferences.append("music") |
|
|
|
|
|
duration = 7 |
|
if "week" in user_message: |
|
duration = 7 |
|
elif "weekend" in user_message: |
|
duration = 3 |
|
|
|
transportation = "car" |
|
if "fly" in user_message or "plane" in user_message: |
|
transportation = "plane" |
|
elif "rideshare" in user_message: |
|
transportation = "rideshare" |
|
|
|
packing_list = generate_packing_list(duration, preferences, transportation) |
|
context = f"Hey there, dusty friend! I hear you're gearing up for a {duration}-day adventure on the playa. That's awesome! I've put together a packing list tailored just for you, considering your love for {', '.join(preferences)} and your plan to get there by {transportation}. Remember, this is just a starting point - you know yourself best!\n\nHere's what I'd suggest packing:\n\n" + "\n".join(f"- {item}" for item in packing_list) + "\n\nRemember, the playa provides, but it's always better to be prepared. Don't forget to bring your radical self-reliance along with everything else!" |
|
prompt = f"{current_year_info}\n\nUser asked for a packing list. Respond with this information, maintaining the friendly tone and adding your personal touch: {context}" |
|
|
|
elif "weather" in user_message: |
|
weather_forecast = get_weather() |
|
weather_report = format_weather_report(weather_forecast) |
|
if weather_forecast: |
|
context = f"Hey there, playa pal! You're asking about the weather, huh? Well, I've got the latest forecast straight from the desert winds. Here's what Mother Nature has in store for Black Rock City:\n\n{weather_report}\n\nNow, remember, weather on the playa is like a wild art car - it can change direction at any moment! Always be prepared for heat, cold, dust, and maybe even a little rain. Embrace the elements, but stay safe out there!" |
|
else: |
|
context = "Oh no! It seems like the dust storm has interfered with my weather sensors. I couldn't fetch the latest forecast. But hey, that's part of the adventure, right? Always be prepared for anything on the playa - from scorching heat to chilly nights, and of course, those legendary dust storms. Pack for all conditions and embrace the unpredictable nature of the desert!" |
|
prompt = f"{current_year_info}\n\nUser asked about the weather. Respond with this information, maintaining the friendly tone and adding your personal touch: {context}" |
|
|
|
elif "principles" in user_message: |
|
principles_info = "\n".join([f"{principle}: {description}" for principle, description in burning_man_principles.items()]) |
|
context = f"Ah, the 10 Principles! The very heart and soul of Burning Man. These aren't just rules, my dusty friend, they're a way of life on and off the playa. Let me break them down for you in true Burner style:\n\n{principles_info}\n\nRemember, these principles aren't just for Burning Man - they're a blueprint for building a better world. Which one resonates with you the most?" |
|
prompt = f"{current_year_info}\n\nUser asked about the Burning Man principles. Respond with this information, maintaining the friendly tone and adding your personal touch: {context}" |
|
|
|
elif "survival tips" in user_message: |
|
tips = "\n".join([f"- {tip}" for tip in survival_tips]) |
|
context = f"Alright, future dusty warrior! Surviving and thriving on the playa is an art form, and I'm here to help you master it. Here are some tried-and-true survival tips from a seasoned Burner:\n\n{tips}\n\nRemember, the key to survival is preparation, but the key to thriving is participation. Embrace the dust, the heat, and the beautiful chaos. You've got this!" |
|
prompt = f"{current_year_info}\n\nUser asked for survival tips. Respond with this information, maintaining the friendly tone and adding your personal touch: {context}" |
|
|
|
else: |
|
prompt = f"{current_year_info}\n\nUser: {message}\n\nAssistant:" |
|
|
|
bot_message = await chat_with_groq(prompt, history) |
|
|
|
|
|
corrected_message = correct_year(bot_message) |
|
logger.info(f"Corrected message: {corrected_message}") |
|
|
|
return corrected_message |
|
except Exception as e: |
|
logger.error(f"Error in chat_interface: {str(e)}") |
|
burner_error_message = ( |
|
"Whoa there, dusty friend! Looks like a sandstorm just hit our connection. " |
|
"But no worries - we Burners are all about adapting to challenges. " |
|
"Why don't you try asking your question again? Remember, persistence is key on the playa!" |
|
) |
|
return burner_error_message |
|
|
|
|
|
if __name__ == "__main__": |
|
import asyncio |
|
|
|
async def test_chat(): |
|
response = await chat_interface("Tell me about Burning Man", []) |
|
print(response) |
|
|
|
asyncio.run(test_chat()) |