pizza-chatbot / app.py
DocSA's picture
Update app.py
11a71a7 verified
"""
🍕 Чат-бот для піцерії "Мама Міа" - Hugging Face версія
Використовує файл menu.txt для завантаження меню
"""
import os
import gradio as gr
from openai import OpenAI
class PizzaChatBot:
"""Основний клас чат-боту для піцерії"""
def __init__(self):
"""Ініціалізація чат-боту"""
# Отримуємо API ключ з змінних середовища (HF Secrets)
self.api_key = os.getenv('OPENROUTER_API_KEY')
self.base_url = "https://openrouter.ai/api/v1"
self.model = "openai/gpt-oss-20b:free"
self.restaurant_name = "Піцерія 'Мама Міа'"
self.menu = self.load_menu()
# Ініціалізація OpenAI клієнта для OpenRouter
if self.api_key and self.api_key != 'your_api_key_here':
self.client = OpenAI(
base_url=self.base_url,
api_key=self.api_key
)
print(f"✅ {self.restaurant_name} чат-бот ініціалізовано")
else:
self.client = None
print("⚠️ API ключ не налаштовано - використовується демо режим")
def load_menu(self):
"""Завантажує меню з файлу menu.txt"""
try:
with open('menu.txt', 'r', encoding='utf-8') as file:
content = file.read()
print(f"✅ Меню завантажено з файлу ({len(content)} символів)")
return content
except FileNotFoundError:
print("❌ Файл menu.txt не знайдено - використовується базове меню")
return self.get_fallback_menu()
except Exception as e:
print(f"❌ Помилка завантаження меню: {e}")
return self.get_fallback_menu()
def get_fallback_menu(self):
"""Резервне меню, якщо файл не завантажується"""
return """🍕 ПІЦЕРІЯ "МАМА МІА" 🍕
📋 ОСНОВНЕ МЕНЮ:
🍕 Маргарита (30см) - 250 грн
🍕 Пепероні (30см) - 320 грн
🍕 Барбекю Чікен (30см) - 450 грн
🍕 Морська (30см) - 520 грн
🥗 Салат Цезар - 180 грн
🥤 Кока-кола - 35 грн
🍰 Тірамісу - 120 грн
⏰ РЕЖИМ РОБОТИ: 11:00 - 23:00
🚚 ДОСТАВКА: Безкоштовно від 400 грн
📞 ТЕЛЕФОН: +38 (044) 123-45-67"""
def get_system_prompt(self):
"""Створює системний промпт для LLM"""
return f"""Ти - дружелюбний помічник піцерії "{self.restaurant_name}".
Твоя роль:
- Допомагати клієнтам з вибором піци та страв з меню
- Надавати точну інформацію про ціни та інгредієнти
- Розповідати про режим роботи, доставку та акції
- Приймати замовлення та відповідати на запитання
- Бути ввічливим, корисним та дружелюбним
Важливі правила:
- Завжди говори українською мовою
- Використовуй емодзі для дружнього спілкування 🍕😊
- Базуйся тільки на інформації з меню
- Якщо не знаєш відповіді - направляй до телефону
- Пропонуй популярні страви та акції
Ось повне меню та інформація про піцерію:
{self.menu}
Починай кожну розмову привітно та будь готовий допомогти!"""
def chat_response(self, message, history):
"""Обробляє повідомлення користувача та повертає відповідь"""
# Якщо немає API ключа - демо режим
if not self.client:
return self.demo_response(message)
try:
# Формуємо історію розмови для API
messages = [{"role": "system", "content": self.get_system_prompt()}]
# Додаємо історію розмови (останні 10 повідомлень для економії токенів)
recent_history = history[-10:] if len(history) > 10 else history
for human, assistant in recent_history:
if human and assistant:
messages.append({"role": "user", "content": human})
messages.append({"role": "assistant", "content": assistant})
# Додаємо поточне повідомлення
messages.append({"role": "user", "content": message})
# Отримуємо відповідь від LLM через OpenRouter
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
max_tokens=800,
temperature=0.7
)
return response.choices[0].message.content
except Exception as e:
print(f"❌ Помилка API: {e}")
return f"Вибачте, виникла технічна проблема 😔 Зателефонуйте нам: +38 (044) 123-45-67"
def demo_response(self, message):
"""Демо відповіді без API"""
message_lower = message.lower()
if any(word in message_lower for word in ['меню', 'піца', 'страв']):
return """🍕 Ось наше меню:
**ПІЦИ:**
• Маргарита (30см) - 250 грн
• Пепероні (30см) - 320 грн
• Барбекю Чікен (30см) - 450 грн
• Морська (30см) - 520 грн
Що вас цікавить? 😊"""
elif any(word in message_lower for word in ['ціна', 'скільки', 'коштує']):
return "💰 Ціни на піци від 250 до 520 грн. Безкоштовна доставка від 400 грн! Що саме вас цікавить?"
elif any(word in message_lower for word in ['доставка', 'час', 'швидко']):
return "🚚 Доставка 30-45 хвилин. Безкоштовно від 400 грн, інакше 50 грн. Працюємо з 11:00 до 23:00!"
elif any(word in message_lower for word in ['телефон', 'контакт', 'адреса']):
return "📞 Телефон: +38 (044) 123-45-67\n📍 Адреса: вул. Хрещатик, 25, Київ\n⏰ Режим: 11:00 - 23:00"
else:
return f"""Привіт! 👋 Я помічник піцерії "Мама Міа".
Можу допомогти з:
🍕 Меню та цінами
📞 Інформацією про доставку
⏰ Режимом роботи
📋 Оформленням замовлення
Що вас цікавить? 😊
*Примітка: Зараз працює демо-режим. Для повного функціоналу потрібен API ключ.*"""
def create_interface(self):
"""Створює Gradio інтерфейс для Hugging Face"""
# Кастомні стилі
custom_css = """
.gradio-container {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.header-banner {
background: linear-gradient(135deg, #ff6b6b, #feca57, #48cab2);
border-radius: 15px;
padding: 25px;
text-align: center;
margin-bottom: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.info-card {
background-color: #f8f9fa;
border-radius: 10px;
padding: 15px;
margin-top: 15px;
border-left: 4px solid #ff6b6b;
}
"""
with gr.Blocks(
css=custom_css,
title=f"{self.restaurant_name} - AI Чат-бот",
theme=gr.themes.Soft()
) as interface:
# Заголовок з градієнтом
gr.HTML(f"""
<div class="header-banner">
<h1 style="color: white; margin: 0; font-size: 2.5em;">🍕 {self.restaurant_name}</h1>
<h3 style="color: white; margin: 15px 0; font-size: 1.3em;">
Привіт! Я AI-помічник, готовий допомогти з замовленням 😊
</h3>
<p style="color: white; margin: 0; font-size: 1.1em;">
Запитайте про меню, ціни, доставку або зробіть замовлення!
</p>
</div>
""")
# Основний чат
chatbot = gr.Chatbot(
height=500,
placeholder="🍕 Привіт! Що вас цікавить сьогодні?",
label="💬 Розмова з піца-ботом",
avatar_images=("👤", "🤖")
)
# Поле вводу та кнопка відправки
with gr.Row():
msg = gr.Textbox(
placeholder="Введіть ваше повідомлення тут...",
label="",
lines=2,
scale=4,
container=False
)
send_btn = gr.Button(
"Відправити 📤",
variant="primary",
scale=1,
size="lg"
)
# Додаткові кнопки
with gr.Row():
clear_btn = gr.Button("Очистити чат 🗑️", variant="secondary")
# Швидкі запитання
gr.Examples(
examples=[
"Покажіть меню піци",
"Яка найпопулярніша піца?",
"Скільки коштує доставка?",
"Режим роботи піцерії",
"Хочу замовити 2 піци Маргарита",
"Які у вас акції?"
],
inputs=msg,
label="💡 Швидкі запитання (натисніть для вибору):"
)
# Інформаційна картка
gr.HTML("""
<div class="info-card">
<h4 style="margin-top: 0; color: #333;">📋 Основна інформація:</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px;">
<div>
<strong>📍 Адреса:</strong><br>
вул. Хрещатик, 25, Київ
</div>
<div>
<strong>📞 Телефон:</strong><br>
+38 (044) 123-45-67
</div>
<div>
<strong>⏰ Режим роботи:</strong><br>
Щодня 11:00 - 23:00
</div>
<div>
<strong>🚚 Доставка:</strong><br>
Безкоштовно від 400 грн
</div>
</div>
</div>
""")
# Обробники подій
def user_message(message, history):
"""Додає повідомлення користувача до чату"""
if message.strip():
return "", history + [[message, None]]
return message, history
def bot_response(history):
"""Генерує відповідь бота"""
if history and history[-1][0]:
message = history[-1][0]
response = self.chat_response(message, history[:-1])
history[-1][1] = response
return history
def clear_chat():
"""Очищає історію чату"""
return []
# Прив'язування подій
msg.submit(
user_message,
[msg, chatbot],
[msg, chatbot],
queue=False
).then(
bot_response,
chatbot,
chatbot
)
send_btn.click(
user_message,
[msg, chatbot],
[msg, chatbot],
queue=False
).then(
bot_response,
chatbot,
chatbot
)
clear_btn.click(clear_chat, None, chatbot, queue=False)
return interface
def main():
"""Головна функція для запуску на Hugging Face Spaces"""
print("🚀 Ініціалізація піца-чат-боту для Hugging Face...")
# Створення екземпляру чат-боту
bot = PizzaChatBot()
# Створення інтерфейсу
interface = bot.create_interface()
print("✅ Інтерфейс створено, запускаємо...")
return interface
# Запуск для Hugging Face Spaces
if __name__ == "__main__":
demo = main()
demo.launch(
server_name="0.0.0.0", # Для Hugging Face
server_port=7860, # Стандартний порт HF
share=False, # HF автоматично надає публічний доступ
debug=False # Вимкнути debug в продакшені
)