File size: 14,719 Bytes
c8ba8e7
 
 
 
 
72c85ee
 
c8ba8e7
72c85ee
c8ba8e7
 
 
 
 
 
 
 
11a71a7
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
72c85ee
c8ba8e7
 
 
 
72c85ee
c8ba8e7
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
72c85ee
c8ba8e7
72c85ee
c8ba8e7
72c85ee
c8ba8e7
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
72c85ee
c8ba8e7
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
 
 
 
 
 
 
 
 
 
 
 
 
72c85ee
c8ba8e7
72c85ee
c8ba8e7
 
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
 
72c85ee
c8ba8e7
72c85ee
c8ba8e7
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
"""
🍕 Чат-бот для піцерії "Мама Міа" - 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 в продакшені
    )