File size: 6,207 Bytes
87848d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3efd8fa
87848d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Модуль для взаємодії з Open Router API.
"""

import os
from openai import OpenAI
from typing import Optional
from dotenv import load_dotenv

# Завантажуємо змінні з .env файлу
load_dotenv()

# System prompt для асистента піцерії
SYSTEM_PROMPT = """Ти - дружній асистент піцерії "Смачна Піца". Твоя задача - допомагати клієнтам з інформацією про меню.

ВАЖЛИВІ ПРАВИЛА:
- Відповідай ТІЛЬКИ українською мовою
- Будь ввічливим, дружнім та корисним
- Використовуй ТІЛЬКИ інформацію з наданого меню
- Якщо клієнт запитує щось не пов'язане з меню (погода, новини, інші теми), ввічливо поясни, що ти можеш допомогти тільки з питаннями про меню піцерії
- Відповідай коротко та по суті
- Якщо клієнт не впевнений що замовити, запропонуй варіанти з меню
"""


class OpenRouterClient:
    """Клієнт для роботи з Open Router API."""
    
    def __init__(self):
        """Ініціалізація клієнта з перевіркою API ключа."""
        self.api_key = os.getenv("OPENROUTER_API_KEY")
        if not self.api_key:
            raise ValueError(
                "❌ OPENROUTER_API_KEY не встановлено. "
                "Додайте API ключ в environment variables."
            )
        
        # Ініціалізуємо OpenAI клієнт з Open Router endpoint
        self.client = OpenAI(
            base_url="https://openrouter.ai/api/v1",
            api_key=self.api_key
        )
        
        self.model = "deepseek/deepseek-r1-distill-llama-70b:free"
        self.temperature = 0.7
        self.max_tokens = 500

    
    def create_chat_completion(
        self,
        user_message: str,
        menu_context: str,
        conversation_history: Optional[list] = None
    ) -> str:
        """
        Відправляє запит до LLM та отримує відповідь.
        
        Args:
            user_message: Повідомлення користувача
            menu_context: Контекст меню піцерії
            conversation_history: Історія розмови (опціонально)
            
        Returns:
            Відповідь від LLM
            
        Raises:
            requests.exceptions.RequestException: При помилках API
            Exception: При інших помилках
        """
        try:
            # Формуємо повідомлення для API
            messages = [
                {
                    "role": "system",
                    "content": f"{SYSTEM_PROMPT}\n\nМЕНЮ ПІЦЕРІЇ:\n{menu_context}"
                }
            ]
            
            # Додаємо історію розмови якщо є
            if conversation_history:
                for user_msg, bot_msg in conversation_history:
                    messages.append({"role": "user", "content": user_msg})
                    messages.append({"role": "assistant", "content": bot_msg})
            
            # Додаємо поточне повідомлення користувача
            messages.append({"role": "user", "content": user_message})
            
            # Відправляємо запит через OpenAI SDK
            completion = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=self.temperature,
                max_tokens=self.max_tokens,
                timeout=10.0
            )
            
            # Отримуємо відповідь
            assistant_message = completion.choices[0].message.content
            return assistant_message.strip()
        
        except Exception as e:
            error_message = str(e).lower()
            
            # Обробка специфічних помилок
            if "rate limit" in error_message or "429" in error_message:
                return "❌ Перевищено ліміт запитів. Будь ласка, спробуйте через хвилину."
            
            if "unauthorized" in error_message or "401" in error_message:
                return "❌ Помилка автентифікації. Перевірте API ключ."
            
            if "timeout" in error_message:
                return "❌ Час очікування відповіді вичерпано. Спробуйте ще раз."
            
            if "connection" in error_message:
                return "❌ Помилка з'єднання. Перевірте інтернет-з'єднання."
            
            # Загальна помилка
            return f"❌ Виникла помилка: {str(e)}"


# Глобальний екземпляр клієнта
_client_instance = None


def get_client() -> OpenRouterClient:
    """Отримати глобальний екземпляр клієнта (singleton pattern)."""
    global _client_instance
    if _client_instance is None:
        _client_instance = OpenRouterClient()
    return _client_instance


def create_chat_completion(
    user_message: str,
    menu_context: str,
    conversation_history: Optional[list] = None
) -> str:
    """
    Зручна функція для створення chat completion.
    
    Args:
        user_message: Повідомлення користувача
        menu_context: Контекст меню піцерії
        conversation_history: Історія розмови (опціонально)
        
    Returns:
        Відповідь від LLM
    """
    client = get_client()
    return client.create_chat_completion(user_message, menu_context, conversation_history)