U
    h                     @   sx   d Z ddlZddlZddlZddlZddlmZmZmZm	Z	 ddl
Z
ddl
mZ ddlmZ eeZG dd dZdS )uN   
Модуль для работы с OpenAI API в AI-КАЛОРИЯ боте
    N)DictAnyOptionalList)OpenAI)Configc                   @   s   e Zd ZdZedddZeee dddZee	ee
f dd	d
ZeedddZee	ee
f dddZeee dddZeeeedddZeedddZee	ee
f dddZeeedddZeeedddZdd  Zd!S )"OpenAIClientu.   Клиент для работы с OpenAI APIapi_keyc              	   C   s   t  | _t  | _| jd rd| jd  d| jd  d| jd  d| jd  }td	| jd  d| jd   tj|d
d| _	t
|| j	d| _nt
|d| _d| _	td dS )u0   Инициализация клиента OpenAIenabledzhttp://login:password@serverportu'   Используется прокси: g      >@)proxiestimeout)r
   http_clientr	   Nu2   OpenAI клиент инициализирован)r   get_openai_configconfigget_proxy_configproxy_configloggerinfohttpxZClientr   r   client)selfr
   	proxy_url r   N/var/www/u0236315/data/www/consultsolution.ru/ai-calories-app/openai_client.py__init__   s     


4"
zOpenAIClient.__init__)
audio_datareturnc              
   C   s   zTt |}d|_| jjjj| jd |dd}|j	 }t
d|  |rP|ndW S  tk
r } zt
d|  W Y dS d}~X Y nX dS )uL   Конвертация голосового сообщения в текстz	voice.oggwhisper_modelru)modelfilelanguageu   Распознан текст: Nu9   Ошибка при распознавании речи: )ioBytesIOnamer   audioZtranscriptionscreater   textstripr   r   	Exceptionerror)r   r"   Z
audio_fileZ
transcriptr.   er   r   r    speech_to_text1   s    


zOpenAIClient.speech_to_text)r.   r#   c              
   C   sl   z&|  |}td|  | |W S  tk
rf } z"td|  ddd W Y S d}~X Y nX dS )uL   Анализ текста с описанием еды с помощью GPTu%   Обработанный текст: +   Ошибка при анализе еды: F5   Ошибка при обработке запросаsuccessmessageN)smart_request_processingr   r   _analyze_food_intake_internalr0   r1   )r   r.   processed_textr2   r   r   r    analyze_food_intakeH   s    
z OpenAIClient.analyze_food_intakec              
   C   s   zTd}d| }| j jjj| jd d|dd|dgddd	}|jd
 jj }|W S  t	k
r } zt
d|  | W Y S d}~X Y nX dS )uW   Умная обработка запроса с попыткой исправленияu  
Ты - умный помощник по анализу запросов о еде. Твоя задача - понять и исправить запрос пользователя, если он некорректен или неполный.

ПРАВИЛА ОБРАБОТКИ:
1. Если запрос понятен и корректен - верни его как есть
2. Если запрос неполный - попытайся дополнить его логично
3. Если запрос некорректен - исправь его
4. Если запрос неясен - попытайся угадать наиболее вероятное значение
5. Всегда возвращай ТОЛЬКО исправленный запрос, без дополнительных комментариев

ПРИМЕРЫ:
"йогурт экспонента" -> "йогурт экспонента"
"съел яблоко" -> "яблоко"
"выпил стакан молока" -> "стакан молока"
"капучино" -> "капучино"
"овсянка" -> "овсянка"
"гречка с молоком" -> "гречка с молоком"
"непонятный текст" -> "овсянка" (если это наиболее вероятно)
uF   Обработай и исправь этот запрос о еде: r&   systemrolecontentuserd   333333?r&   messages
max_tokenstemperaturer   uB   Ошибка при умной обработке запроса: Nr   chatcompletionsr-   r   choicesr8   r@   r/   r0   r   r1   )r   r.   system_promptuser_promptresponser;   r2   r   r   r    r9   Y   s     


z%OpenAIClient.smart_request_processingc           
   
      s0  zd}d| }| j jjj| jd d|dd|dg| jd | jd d	}|jd
 jj }t	
d|  z\t| t tstdd krtd drt fdddD std W W S  tjk
r  } z4t	d|  t	d|  ddd W Y W S d}~X Y n tk
r } zt	d|  t	d|  zdd
dl}|d||j}|r| }	t|	 t trd krt	
d  W  W Y (W S W n   Y nX ddd W Y W S d}~X Y nX W nB tk
r* } z"t	d|  ddd W Y S d}~X Y nX dS )u5   Внутренний метод анализа едыuQ  
Ты - эксперт по питанию и анализу еды. Твоя задача - анализировать сообщения пользователей о том, что они съели или выпили, и извлекать структурированную информацию.

ВАЖНО: Отвечай ТОЛЬКО в формате JSON. Никакого дополнительного текста.

Формат ответа:
{
    "success": true/false,
    "food_name": "название продукта",
    "amount": число,
    "unit": "единица измерения",
    "calories": число,
    "message": "сообщение об ошибке (если success=false)"
}

Правила анализа:
1. Если в сообщении нет информации о количестве - success=false, message="Укажите количество (граммы, миллилитры, штуки)"
2. Если не понятно что съели - success=false, message="Укажите что именно вы съели"
3. Если информации достаточно - success=true, извлеки данные
4. Для калорий используй средние значения для продуктов
5. Единицы измерения: "г", "мл", "шт", "кусок", "порция"
6. Название продукта должно быть понятным и конкретным

СПЕЦИАЛЬНЫЕ ПРАВИЛА ДЛЯ РАЗМЕРОВ ПОРЦИЙ:
- "тарелка" или "миска" = 350 мл
- "маленькая порция" = 250 мл  
- "большая порция" = 500 мл
- "стакан" = 250 мл
- "чашка" = 200 мл
- "ложка" = 15 мл
- "столовая ложка" = 15 мл
- "чайная ложка" = 5 мл

ПРАВИЛА ДЛЯ ШТУЧНЫХ ПРОДУКТОВ:
- Если указано количество в штуках (шт), используй "шт" как единицу измерения
- Для роллов: 1 ролл = примерно 50-80 ккал
- Для пиццы: 1 кусок = примерно 200-300 ккал
- Для бутербродов: 1 штука = примерно 150-250 ккал

ПРИОРИТЕТНЫЕ ПРАВИЛА:
- Если в запросе есть слово "калорий" или "ккал", используй указанное пользователем количество калорий
- Если пользователь сам указал точное количество калорий, это имеет приоритет над стандартными значениями
- Пример: "овсянка 200 калорий" -> используй 200 ккал, а не стандартные 150

ПРАВИЛА ДЛЯ НЕУКАЗАННОГО КОЛИЧЕСТВА:
- Если продукт назван без указания количества, считай как 1 порцию
- "квашеная капуста" = 1 порция (примерно 200г)
- "салат" = 1 порция (примерно 200г)
- "овощи" = 1 порция (примерно 200г)
- "яблоко" = 1 штука (примерно 150г)
- "банан" = 1 штука (примерно 120г)
- "мороженное" = 1 порция (примерно 100г)
- "суп" = 1 порция (примерно 250мл)
- "чай" = 1 чашка (примерно 200мл, 50 ккал)
- "кофе" = 1 чашка (примерно 200мл, 50 ккал)

ПРАВИЛА ДЛЯ ГОТОВЫХ БЛЮД:
- Если блюдо содержит несколько ингредиентов (например, "картофель с мясом", "рис с овощами"), считай как 1 полную порцию готового блюда
- "картофель с мясом" = 1 порция (примерно 300г, 400 ккал)
- "рис с мясом" = 1 порция (примерно 300г, 350 ккал)
- "макароны с сыром" = 1 порция (примерно 250г, 300 ккал)
- "гречка с мясом" = 1 порция (примерно 250г, 300 ккал)
- "овощи с мясом" = 1 порция (примерно 300г, 250 ккал)
- "салат с мясом" = 1 порция (примерно 200г, 200 ккал)
- "суп с мясом" = 1 порция (примерно 300мл, 200 ккал)
- "борщ с мясом" = 1 порция (примерно 300мл, 250 ккал)
- "плов" = 1 порция (примерно 300г, 400 ккал)
- "жаркое" = 1 порция (примерно 300г, 350 ккал)
- "рагу" = 1 порция (примерно 300г, 300 ккал)
- "тушеные овощи с мясом" = 1 порция (примерно 300г, 250 ккал)

ПРАВИЛА ДЛЯ ФАСТФУДА И КОМПЛЕКСНЫХ БЛЮД:
- "бургер с картошкой" = 1 порция (примерно 300г + 150г картошки, 600 ккал)
- "бургер с картофелем" = 1 порция (примерно 300г + 150г картошки, 600 ккал)
- "бургер с фри" = 1 порция (примерно 300г + 150г картошки, 600 ккал)
- "бургер с картофелем фри" = 1 порция (примерно 300г + 150г картошки, 600 ккал)
- "кола и бургер" = 1 порция (примерно 250мл колы + 300г бургера, 500 ккал)
- "кола бургер и картошка" = 1 порция (примерно 250мл + 300г + 150г, 700 ккал)
- "кола бургер и 2 мафина" = 1 порция (примерно 250мл + 300г + 2×100г, 800 ккал)
- "кола фри и бургер" = 1 порция (примерно 250мл + 150г + 300г, 700 ккал)

ПРАВИЛА ДЛЯ ДЕСЕРТОВ И ВЫПЕЧКИ:
- "пирог с яблоком" = 1 порция (примерно 150г, 300 ккал)
- "пирог с яблоком и чаем" = 1 порция (примерно 150г + 200мл чая, 300 ккал)
- "торт с кофе" = 1 порция (примерно 100г + 200мл кофе, 400 ккал)
- "печенье с молоком" = 1 порция (примерно 50г + 200мл молока, 200 ккал)
- "блины с вареньем" = 1 порция (примерно 200г, 350 ккал)
- "оладьи с медом" = 1 порция (примерно 150г, 250 ккал)
- "вафли с сиропом" = 1 порция (примерно 100г, 300 ккал)
- "круассан с кофе" = 1 порция (примерно 60г + 200мл кофе, 250 ккал)
- "пончик с чаем" = 1 порция (примерно 80г + 200мл чая, 200 ккал)
- "кекс с молоком" = 1 порция (примерно 100г + 200мл молока, 300 ккал)

ПРАВИЛА ДЛЯ КОМБИНИРОВАННЫХ БЛЮД:
- Если блюдо содержит несколько компонентов (например, "пирог с яблоком и чаем"), считай как 1 полную порцию комплексного блюда
- "завтрак с кофе" = 1 порция (примерно 300г + 200мл кофе, 400 ккал)
- "обед с супом" = 1 порция (примерно 400г + 300мл супа, 500 ккал)
- "ужин с салатом" = 1 порция (примерно 300г + 200г салата, 400 ккал)
- "перекус с чаем" = 1 порция (примерно 100г + 200мл чая, 150 ккал)
- "полдник с соком" = 1 порция (примерно 150г + 250мл сока, 200 ккал)

ПРАВИЛА ДЛЯ ОТДЕЛЬНЫХ КОМПОНЕНТОВ:
- Если пользователь указывает количество для отдельного компонента (например, "5 шт хинкали"), считай только этот компонент
- "5 шт хинкали" = 5 штук хинкали (примерно 5 х 80 ккал = 400 ккал)
- "3 шт хачапури" = 3 штуки хачапури (примерно 3 х 300 ккал = 900 ккал)
- "2 шт пельмени" = 2 штуки пельмени (примерно 2 х 30 ккал = 60 ккал)
- "4 шт роллы" = 4 штуки роллов (примерно 4 х 50 ккал = 200 ккал)
- "6 шт суши" = 6 штук суши (примерно 6 х 50 ккал = 300 ккал)
- "2 шт блины" = 2 штуки блинов (примерно 2 х 100 ккал = 200 ккал)
- "3 шт вареники" = 3 штуки вареников (примерно 3 х 40 ккал = 120 ккал)
- "флэт вайт" = 1 порция (примерно 200мл)
- "капучино" = 1 порция (примерно 200мл)
- "латте" = 1 порция (примерно 200мл)
- "эспрессо" = 1 порция (примерно 30мл)
- "американо" = 1 порция (примерно 200мл)
- "макиато" = 1 порция (примерно 200мл)
- "мокко" = 1 порция (примерно 200мл)
- "фраппе" = 1 порция (примерно 200мл)
- "овсянка" = 1 порция (примерно 200г)
- "гречка с молоком" = 1 порция (примерно 250г)
- "рис с молоком" = 1 порция (примерно 250г)
- "манная каша" = 1 порция (примерно 200г)
- "пшенная каша" = 1 порция (примерно 200г)
- "перловая каша" = 1 порция (примерно 200г)
- "ячневая каша" = 1 порция (примерно 200г)
- "кукурузная каша" = 1 порция (примерно 200г)
- "булгур" = 1 порция (примерно 200г)
- "киноа" = 1 порция (примерно 200г)
- "йогурт" = 1 порция (примерно 150г)
- "кефир" = 1 стакан (примерно 250мл)
- "ряженка" = 1 стакан (примерно 250мл)
- "сметана" = 1 порция (примерно 50г)
- "творог" = 1 порция (примерно 200г)
- "сыр" = 1 порция (примерно 50г)
- "масло" = 1 порция (примерно 10г)

ПРАВИЛА ДЛЯ РАЗМЕРОВ:
- Если есть размер (стаканчик, порция, кусок, тарелка), используй его
- "стаканчик мороженного" = 1 стаканчик
- "порция салата" = 1 порция
- "кусок пиццы" = 1 кусок
- "тарелка супа" = 1 тарелка (350 мл)
- "стакан сока" = 1 стакан (250 мл)

ДОПОЛНИТЕЛЬНЫЕ ПРАВИЛА:
- Квашеная капуста = примерно 20 ккал на 100г
- Салат = примерно 15 ккал на 100г
- Овощи = примерно 25 ккал на 100г
- Вода = 0 ккал
- Чай без сахара = 0 ккал
- Кофе без сахара = 0 ккал
- Сок = примерно 50 ккал на 100мл
- Молоко = примерно 50 ккал на 100мл
- Компот = примерно 40 ккал на 100мл
- Морс = примерно 30 ккал на 100мл
- Флэт вайт = примерно 150 ккал на порцию
- Капучино = примерно 120 ккал на порцию
- Латте = примерно 180 ккал на порцию
- Эспрессо = примерно 5 ккал на порцию
- Американо = примерно 10 ккал на порцию
- Макиато = примерно 100 ккал на порцию
- Мокко = примерно 200 ккал на порцию
- Фраппе = примерно 250 ккал на порцию
- Овсянка = примерно 150 ккал на порцию
- Гречка с молоком = примерно 200 ккал на порцию
- Рис с молоком = примерно 180 ккал на порцию
- Манная каша = примерно 120 ккал на порцию
- Пшенная каша = примерно 140 ккал на порцию
- Перловая каша = примерно 130 ккал на порцию
- Ячневая каша = примерно 135 ккал на порцию
- Кукурузная каша = примерно 110 ккал на порцию
- Булгур = примерно 160 ккал на порцию
- Киноа = примерно 170 ккал на порцию
- Йогурт = примерно 80 ккал на порцию
- Кефир = примерно 50 ккал на стакан
- Ряженка = примерно 60 ккал на стакан
- Сметана = примерно 100 ккал на порцию
- Творог = примерно 150 ккал на порцию
- Сыр = примерно 150 ккал на порцию
- Масло = примерно 75 ккал на порцию
- Если продукт не указан явно, но понятен из контекста - анализируй

Примеры:
"Съел тарелку гречки" -> {"success": true, "food_name": "гречка", "amount": 350, "unit": "мл", "calories": 385}
"Выпил стакан молока" -> {"success": true, "food_name": "молоко", "amount": 250, "unit": "мл", "calories": 130}
"Съел маленькую порцию супа" -> {"success": true, "food_name": "суп", "amount": 250, "unit": "мл", "calories": 125}
"Съел большую порцию риса" -> {"success": true, "food_name": "рис", "amount": 500, "unit": "мл", "calories": 550}
"Роллы Филадельфия 4шт" -> {"success": true, "food_name": "роллы Филадельфия", "amount": 4, "unit": "шт", "calories": 280}
"Пицца Маргарита 2 куска" -> {"success": true, "food_name": "пицца Маргарита", "amount": 2, "unit": "кусок", "calories": 500}
"стаканчик мороженного" -> {"success": true, "food_name": "мороженное", "amount": 1, "unit": "стаканчик", "calories": 200}
"порция салата" -> {"success": true, "food_name": "салат", "amount": 1, "unit": "порция", "calories": 150}
"кусок пиццы" -> {"success": true, "food_name": "пицца", "amount": 1, "unit": "кусок", "calories": 250}
"тарелка квашеной капусты" -> {"success": true, "food_name": "квашеная капуста", "amount": 350, "unit": "мл", "calories": 70}
"тарелка салата" -> {"success": true, "food_name": "салат", "amount": 350, "unit": "мл", "calories": 53}
"квашеная капуста" -> {"success": true, "food_name": "квашеная капуста", "amount": 200, "unit": "г", "calories": 40}
"салат" -> {"success": true, "food_name": "салат", "amount": 200, "unit": "г", "calories": 30}
"яблоко" -> {"success": true, "food_name": "яблоко", "amount": 1, "unit": "шт", "calories": 80}
"банан" -> {"success": true, "food_name": "банан", "amount": 1, "unit": "шт", "calories": 100}
"Съел яблоко" -> {"success": true, "food_name": "яблоко", "amount": 1, "unit": "шт", "calories": 80}
"вода" -> {"success": true, "food_name": "вода", "amount": 250, "unit": "мл", "calories": 0}
"сок" -> {"success": true, "food_name": "сок", "amount": 250, "unit": "мл", "calories": 125}
"молоко" -> {"success": true, "food_name": "молоко", "amount": 250, "unit": "мл", "calories": 125}
"компот" -> {"success": true, "food_name": "компот", "amount": 250, "unit": "мл", "calories": 100}
"морс" -> {"success": true, "food_name": "морс", "amount": 250, "unit": "мл", "calories": 75}
"Выпил воду" -> {"success": true, "food_name": "вода", "amount": 250, "unit": "мл", "calories": 0}
"флэт вайт" -> {"success": true, "food_name": "флэт вайт", "amount": 1, "unit": "порция", "calories": 150}
"капучино" -> {"success": true, "food_name": "капучино", "amount": 1, "unit": "порция", "calories": 120}
"латте" -> {"success": true, "food_name": "латте", "amount": 1, "unit": "порция", "calories": 180}
"эспрессо" -> {"success": true, "food_name": "эспрессо", "amount": 1, "unit": "порция", "calories": 5}
"американо" -> {"success": true, "food_name": "американо", "amount": 1, "unit": "порция", "calories": 10}
"макиато" -> {"success": true, "food_name": "макиато", "amount": 1, "unit": "порция", "calories": 100}
"мокко" -> {"success": true, "food_name": "мокко", "amount": 1, "unit": "порция", "calories": 200}
"фраппе" -> {"success": true, "food_name": "фраппе", "amount": 1, "unit": "порция", "calories": 250}
"Выпил капучино" -> {"success": true, "food_name": "капучино", "amount": 1, "unit": "порция", "calories": 120}
"овсянка" -> {"success": true, "food_name": "овсянка", "amount": 1, "unit": "порция", "calories": 150}
"гречка с молоком" -> {"success": true, "food_name": "гречка с молоком", "amount": 1, "unit": "порция", "calories": 200}
"рис с молоком" -> {"success": true, "food_name": "рис с молоком", "amount": 1, "unit": "порция", "calories": 180}
"манная каша" -> {"success": true, "food_name": "манная каша", "amount": 1, "unit": "порция", "calories": 120}
"пшенная каша" -> {"success": true, "food_name": "пшенная каша", "amount": 1, "unit": "порция", "calories": 140}
"перловая каша" -> {"success": true, "food_name": "перловая каша", "amount": 1, "unit": "порция", "calories": 130}
"ячневая каша" -> {"success": true, "food_name": "ячневая каша", "amount": 1, "unit": "порция", "calories": 135}
"кукурузная каша" -> {"success": true, "food_name": "кукурузная каша", "amount": 1, "unit": "порция", "calories": 110}
"булгур" -> {"success": true, "food_name": "булгур", "amount": 1, "unit": "порция", "calories": 160}
"киноа" -> {"success": true, "food_name": "киноа", "amount": 1, "unit": "порция", "calories": 170}
"Съел овсянку" -> {"success": true, "food_name": "овсянка", "amount": 1, "unit": "порция", "calories": 150}
"Съел гречку с молоком" -> {"success": true, "food_name": "гречка с молоком", "amount": 1, "unit": "порция", "calories": 200}
"овсянка 200 калорий" -> {"success": true, "food_name": "овсянка", "amount": 1, "unit": "порция", "calories": 200}
"гречка 300 ккал" -> {"success": true, "food_name": "гречка", "amount": 1, "unit": "порция", "calories": 300}
"яблоко 50 калорий" -> {"success": true, "food_name": "яблоко", "amount": 1, "unit": "шт", "calories": 50}
"банан 80 ккал" -> {"success": true, "food_name": "банан", "amount": 1, "unit": "шт", "calories": 80}
"капучино 150 калорий" -> {"success": true, "food_name": "капучино", "amount": 1, "unit": "порция", "calories": 150}
"йогурт" -> {"success": true, "food_name": "йогурт", "amount": 1, "unit": "порция", "calories": 80}
"кефир" -> {"success": true, "food_name": "кефир", "amount": 1, "unit": "стакан", "calories": 50}
"ряженка" -> {"success": true, "food_name": "ряженка", "amount": 1, "unit": "стакан", "calories": 60}
"сметана" -> {"success": true, "food_name": "сметана", "amount": 1, "unit": "порция", "calories": 100}
"творог" -> {"success": true, "food_name": "творог", "amount": 1, "unit": "порция", "calories": 150}
"сыр" -> {"success": true, "food_name": "сыр", "amount": 1, "unit": "порция", "calories": 150}
"масло" -> {"success": true, "food_name": "масло", "amount": 1, "unit": "порция", "calories": 75}
"Съел йогурт" -> {"success": true, "food_name": "йогурт", "amount": 1, "unit": "порция", "calories": 80}
"Выпил кефир" -> {"success": true, "food_name": "кефир", "amount": 1, "unit": "стакан", "calories": 50}
"йогурт экспонента" -> {"success": true, "food_name": "йогурт экспонента", "amount": 1, "unit": "порция", "calories": 80}
u@   Проанализируй это сообщение о еде: r&   r=   r>   rA   rF   rG   rD   r   u   GPT ответ: u1   Ответ не является объектомr7   u)   Отсутствует поле 'success'c                 3   s   | ]}| kV  qd S )Nr   ).0keyresultr   r    	<genexpr>  s     z=OpenAIClient._analyze_food_intake_internal.<locals>.<genexpr>)	food_nameamountunitcaloriesu_   Отсутствуют обязательные поля для успешного ответаu1   Ошибка парсинга JSON ответа: u   Ответ ИИ: Fux   Не удалось проанализировать информацию о еде. Попробуйте еще раз.r6   Nu.   Ошибка валидации ответа: \{.*\}u&   JSON исправлен успешноr4   r5   )r   rI   rJ   r-   r   rK   r8   r@   r/   r   r   jsonloads
isinstancedict
ValueErrorgetallJSONDecodeErrorr1   researchDOTALLgroupr0   )
r   r.   rL   rM   rN   response_textr2   ra   
json_matchZ
fixed_jsonr   rQ   r    r:      sf     u



 

"z*OpenAIClient._analyze_food_intake_internal)partial_textr#   c              
   C   s   zpd}d| }| j jjj| jd d|dd|dgddd	}|jd
 jj }dd |	dD }|dd W S  t
k
r } ztd|  g  W Y S d}~X Y nX dS )uc   Получение предложений продуктов по частичному текстуuV  
Ты - помощник по питанию. Предложи 5 популярных продуктов, которые могут подходить под описание пользователя.
Отвечай ТОЛЬКО списком продуктов через запятую, без дополнительного текста.
u*   Предложи продукты для: r&   r=   r>   rA      ffffff?rD   r   c                 S   s   g | ]}|  qS r   )r/   )rO   sr   r   r    
<listcomp>  s     z5OpenAIClient.get_food_suggestions.<locals>.<listcomp>,N   u?   Ошибка при получении предложений: )r   rI   rJ   r-   r   rK   r8   r@   r/   splitr0   r   r1   )r   rg   rL   rM   rN   Zsuggestions_textsuggestionsr2   r   r   r    get_food_suggestions  s"    


z!OpenAIClient.get_food_suggestions)rT   rU   rV   r#   c              
   C   s   zd}d| d| d}| j jjj| jd d|dd|dgd	d
d}|jd jj }z"t	|}|| d }	t
|	dW W S  tk
r   td|  Y W dS X W n8 tk
r }
 ztd|
  W Y dS d}
~
X Y nX dS )u3   Расчет калорий для продуктаu  
Ты - эксперт по калорийности продуктов. Рассчитай калории для указанного продукта.
Отвечай ТОЛЬКО числом (калории на 100г/100мл), без дополнительного текста.
u$   Сколько калорий в 100 ?r&   r=   r>   rA   2   皙?rD   r   rB      u9   Не удалось распарсить калории: g        u3   Ошибка при расчете калорий: N)r   rI   rJ   r-   r   rK   r8   r@   r/   floatroundr]   r   r1   r0   )r   rT   rU   rV   rL   rM   rN   Zcalories_textZcalories_per_100total_caloriesr2   r   r   r    calculate_calories  s,    

zOpenAIClient.calculate_calories)rT   r#   c              
   C   s   zTd}d| }| j jjj| jd d|dd|dgddd	}|jd
 jj }|W S  t	k
r } zt
d|  W Y dS d}~X Y nX dS )uK   Получение совета по питанию для продуктаu   
Ты - диетолог. Дай краткий совет по питанию для указанного продукта.
Отвечай кратко (1-2 предложения) на русском языке.
u-   Дай совет по питанию для r&   r=   r>   rA      ri   rD   r   u5   Ошибка при получении совета: u)   Информация недоступнаNrH   )r   rT   rL   rM   rN   advicer2   r   r   r    get_nutrition_advice  s     


z!OpenAIClient.get_nutrition_advicec              
   C   s   zd}d| }| j jjj| jd d|dd|dgddd	}|jd
 jj }zt	
|}|W W S  t	jk
r   ddgdgd Y W S X W nF tk
r } z(td|  ddgdgd W Y S d}~X Y nX dS )u6   Валидация ввода пользователяuh  
Ты - валидатор сообщений о еде. Проверь, содержит ли сообщение достаточно информации.
Отвечай ТОЛЬКО в формате JSON:
{
    "valid": true/false,
    "missing_info": ["что не хватает"],
    "suggestions": ["предложения по улучшению"]
}
u#   Проверь сообщение: r&   r=   r>   rA   rh   rC   rD   r   Fu4   Не удалось проанализироватьu=   Попробуйте быть более конкретным)ZvalidZmissing_inforo   u(   Ошибка при валидации: u   Ошибка обработкиu   Попробуйте позжеN)r   rI   rJ   r-   r   rK   r8   r@   r/   rY   rZ   r`   r0   r   r1   )r   r.   rL   rM   rN   re   rR   r2   r   r   r    validate_food_input  s4    




z OpenAIClient.validate_food_input)	user_textcurrent_recordr#   c                 C   s  zd}d|d  d|d  d|d  d|d	  d
| d}| j jjj| jd d|dd|dgddd}|jd jj }ddl	}|
d|}|rt|d }	|	dk rd}	|	dkrd}	|	W S W dS W n: tk
 r }
 ztd|
  W Y dS d}
~
X Y nX dS )uM   Умное редактирование калорий с помощью ИИun  
Ты - помощник по редактированию записей о еде. Твоя задача - понять, как пользователь хочет изменить калории записи.

ПРАВИЛА:
1. Если пользователь вводит число - используй его
2. Если пользователь говорит "увеличить", "больше", "добавить" - увеличь калории на 20-50%
3. Если пользователь говорит "уменьшить", "меньше", "сделать меньше" - уменьши калории на 20-50%
4. Если пользователь говорит "в два раза больше" - удвой калории
5. Если пользователь говорит "в два раза меньше" - раздели калории на 2
6. Если пользователь говорит "сделать 200 калорий" - используй 200
7. Всегда возвращай ТОЛЬКО число калорий, без дополнительного текста

ПРИМЕРЫ:
"увеличить" -> увеличить на 30%
"уменьшить" -> уменьшить на 30%
"сделать 250 калорий" -> 250
"в два раза больше" -> удвоить
"немного меньше" -> уменьшить на 20%
   
Текущая запись: rT    - rU   rq   rV    (rW   1    ккал)

Пользователь хочет: uW   

Верни новое количество калорий (только число):
r&   r=   r>   rA   rs   rt   rD   r   N\d+(?:\.\d+)?i'  uL   Ошибка при умном редактировании калорий: )r   rI   rJ   r-   r   rK   r8   r@   r/   ra   findallrv   r0   r   r1   )r   r~   r   rL   rM   rN   rR   ra   numbersnew_caloriesr2   r   r   r    smart_calories_editJ  sF    


z OpenAIClient.smart_calories_editc                 C   sb  z d}d|d  d|d  d|d  d|d	  d
| d}| j jjj| jd d|dd|dgddd}|jd jj }ddl	}ddl
}|d||j}	|	r|	d}
|
dddd}
z||
}|W W S  |jk
r   |d|}|rdt|d i Y W S Y W dS X nW dS W n: tk
r\ } ztd|  W Y dS d}~X Y nX dS )u   Умное редактирование записи с помощью ИИ (количество, единицы, калории)ul  
Ты - помощник по редактированию записей о еде. Твоя задача - понять, как пользователь хочет изменить запись.

ПРАВИЛА:
1. Если пользователь вводит число - это может быть новое количество или калории
2. Если пользователь говорит "увеличить порцию", "больше", "добавить" - увеличь количество на 20-50%
3. Если пользователь говорит "уменьшить порцию", "меньше", "сделать меньше" - уменьши количество на 20-50%
4. Если пользователь говорит "в два раза больше" - удвой количество
5. Если пользователь говорит "в два раза меньше" - раздели количество на 2
6. Если пользователь говорит "сделать 200 грамм" - измени количество на 200г
7. Если пользователь говорит "сделать 2 порции" - измени количество на 2 порции
8. Если пользователь говорит "сделать 300 калорий" - измени калории на 300
9. Если пользователь говорит "стакан", "чашка", "тарелка" - измени единицу измерения
10. Всегда возвращай JSON с полями: amount, unit, calories

ОСОБЫЕ ПРАВИЛА ДЛЯ КОМПЛЕКСНЫХ БЛЮД:
- Если запись содержит "и" (например, "хинкали и хачапури"), и пользователь указывает конкретный компонент (например, "2 шт хинкали"), то:
  * Измени количество на указанное пользователем
  * Пересчитай калории пропорционально для всего блюда
  * Например: "2 шт хинкали" для "хинкали и хачапури" = amount: 2, unit: "шт"

ПРИМЕРЫ:
"увеличить порцию" -> увеличить количество на 30%
"уменьшить порцию" -> уменьшить количество на 30%
"сделать 200 грамм" -> amount: 200, unit: "г"
"сделать 2 стакана" -> amount: 2, unit: "стакан"
"сделать 300 калорий" -> calories: 300
"в два раза больше" -> удвоить количество
"немного меньше" -> уменьшить количество на 20%
"2 шт хинкали" для "хинкали и хачапури" -> amount: 2, unit: "шт"
"3 шт хачапури" для "хачапури и хинкали" -> amount: 3, unit: "шт"
r   rT   r   rU   rq   rV   r   rW   r   uq   

Верни JSON с изменениями (только поля, которые нужно изменить):
r&   r=   r>   rA   rB   rt   rD   r   NrX   z,}}z,]]r   uJ   Ошибка при умном редактировании записи: )r   rI   rJ   r-   r   rK   r8   r@   r/   rY   ra   rb   rc   rd   replacerZ   r`   r   rv   r0   r   r1   )r   r~   r   rL   rM   rN   rR   rY   ra   rf   Zjson_strchangesr   r2   r   r   r    smart_record_edit  sP    !




zOpenAIClient.smart_record_editc                 C   s   | j r| j   td dS )u$   Закрытие HTTP клиентаu   HTTP клиент закрытN)r   closer   r   )r   r   r   r    r     s    
zOpenAIClient.closeN)__name__
__module____qualname____doc__strr!   bytesr   r3   r   r   r<   r9   r:   r   rp   rv   ry   r|   r}   r\   r   r   r   r   r   r   r    r      s   *  @#.=Rr   )r   loggingrY   r)   r   typingr   r   r   r   Zopenair   r   r   	getLoggerr   r   r   r   r   r   r    <module>   s   
