chatgpt_bot/bot/handlers/user/user_handlers.py
2024-10-10 13:08:58 +03:00

340 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import csv
from aiogram.fsm.context import FSMContext
from bot.handlers.user.states import ChooseModelState, SendMessageState
import time
from db.db import *
from aiogram import Router, types, F
from aiogram.filters import CommandStart, Command
from aiogram.types import LabeledPrice, PreCheckoutQuery, InlineKeyboardButton, FSInputFile
from aiogram.utils.keyboard import InlineKeyboardBuilder
from db.db import user_exists, add_user_to_db, set_curren_model, get_temp_prompts
from bot.handlers.user.model_processing import PayCallBack, BuyCallBack, ChooseCallBack
from bot.handlers.user.page_processing import get_page_content
from bot.kbs.inline import PageCallBack
from config import shop_api_token, admins
from bot.utils.openai_tasks import get_model_suggestion_from_openai, get_answer_to_question
user = Router()
@user.message(CommandStart())
async def start(message: types.Message, state: FSMContext):
await state.clear()
# TODO
isAdded = await user_exists(message.from_user.id)
if not isAdded:
# Извлекаем информацию о пользователе
first_name = message.from_user.first_name or ""
last_name = message.from_user.last_name or ""
user_name = message.from_user.username or ""
# Добавляем пользователя в базу данных
await add_user_to_db(
user_id=message.from_user.id,
first_name=first_name,
last_name=last_name,
user_name=user_name
)
text, reply_markup = await get_page_content(page=0,name="main", user_id=message.from_user.id)
await message.answer(text, reply_markup=reply_markup)
@user.callback_query(PageCallBack.filter())
async def user_pages(callback: types.CallbackQuery, callback_data: PageCallBack, state: FSMContext):
await state.clear()
text, reply_markup = await get_page_content(
page=callback_data.page,
name=callback_data.page_name,
user_id=callback.from_user.id,
)
await callback.message.edit_text(text, reply_markup=reply_markup)
await callback.answer()
@user.callback_query(ChooseCallBack.filter())
async def choose(callback: types.CallbackQuery, callback_data: ChooseCallBack):
await set_curren_model(user_id=callback.from_user.id, name_of_model=callback_data.name)
text, reply_markup = await get_page_content(
page=2,
user_id=callback.from_user.id,
name='tarif',
)
await callback.message.edit_text(text, reply_markup=reply_markup)
await callback.answer()
@user.message(Command(commands=['tarif']))
async def tarif(message: types.Message):
# Получаем текст и клавиатуру для страницы тарифа
text, reply_markup = await get_page_content(
page=2,
user_id=message.from_user.id, # Используем message.from_user.id вместо callback
name='tarif',
)
# Отправляем новое сообщение с текстом и кнопками
await message.answer(text, reply_markup=reply_markup)
@user.callback_query(BuyCallBack.filter())
async def buy(callback: types.CallbackQuery, callback_data: BuyCallBack):
kbds = InlineKeyboardBuilder()
buttons = [
InlineKeyboardButton(text="Купить", callback_data=PayCallBack(
name=callback_data.name,
option_of_model=callback_data.option_of_model,
tokens=callback_data.tokens,
amount=callback_data.amount
).pack()),
InlineKeyboardButton(text="⬅️Назад", callback_data=PageCallBack(page=2, page_name="tarif").pack()),
]
for button in buttons:
kbds.add(button)
await callback.message.edit_text(
text = f"Модель: {callback_data.name}\nТариф: {callback_data.option_of_model}\nКол-ов запросов: {callback_data.tokens}\nСтоимость: {callback_data.amount}RUB",
reply_markup=kbds.adjust(*(1,)).as_markup()
)
await callback.answer()
@user.callback_query(PayCallBack.filter())
async def pay(callback: types.CallbackQuery, callback_data: PayCallBack):
temp = await callback.message.bot.send_invoice(
chat_id=callback.from_user.id,
description=f'{callback_data.tokens} токенов за {callback_data.amount} RUB для модели {callback_data.name}',
title=f'{callback_data.option_of_model} подписка на {callback_data.name}',
payload=f'sub_{callback_data.name}_{callback.from_user.id}_{callback_data.tokens}',
# Добавляем id пользователя и количество токенов в payload
provider_token=shop_api_token,
start_parameter='test',
currency="RUB",
prices=[LabeledPrice(
label=f'Оплата токенов для {callback_data.option_of_model}',
amount=int(callback_data.amount) * 100,
)],
)
# if temp.successful_payment is None:
# await callback.bot.send_message(chat_id=callback.from_user.id,text="Something went wrong")
@user.pre_checkout_query()
async def process_pre_checkout_query(pre_checkout_query: PreCheckoutQuery):
await pre_checkout_query.answer(ok=True)
@user.message(F.successful_payment)
async def process_payment(message: types.Message):
if message.successful_payment is None:
await message.bot.send_message(chat_id=message.from_user.id,text="Что то пошло не так")
return
payload_data = message.successful_payment.invoice_payload.split('_')
if len(payload_data) != 4:
return # Не валидный payload
model_name = payload_data[1] # Имя модели
user_id = int(payload_data[2]) # ID пользователя
tokens = int(payload_data[3]) # Количество токенов
await add_tokens_to_user(user_id, model_name, tokens)
time.sleep(2)
await message.bot.send_message(chat_id=message.from_user.id,
text="Спасибо, что пользуетесь нашим сервисом!")
await message.bot.send_message(chat_id=message.from_user.id,
text="Для работы с chatGPT отправьте текст с вашим вопросом и получите на него ответ)")
await set_curren_model(user_id, model_name)
@user.message(Command(commands=["failed"]))
async def process_payment(message: types.Message):
await message.bot.send_message(chat_id=message.from_user.id,
text="Что-то пошло не так( Попробуйте еще раз!")
text, reply_markup = await get_page_content(page=0, name="main", user_id=message.from_user.id)
await message.bot.send_message(
chat_id=message.from_user.id,
text=text,
reply_markup=reply_markup,
)
@user.callback_query(lambda c: c.data == 'choose')
async def chat_test_gpt(callback: types.CallbackQuery, state: FSMContext):
kbds = InlineKeyboardBuilder()
kbds.add(InlineKeyboardButton(
text="⬅️Назад",
callback_data=PageCallBack(
page=3,
page_name='more_about_models',
).pack()
))
await callback.message.edit_text("Вы находитесь в разделе подбора модели. Опишите ваши задачи, и я помогу выбрать модель.", reply_markup=kbds.adjust(*(1,)).as_markup())
await callback.answer()
await state.set_state(ChooseModelState.choosing_model)
@user.message(ChooseModelState.choosing_model)
async def process_model_question(message: types.Message):
user_id = message.from_user.id
remaining_queries = await get_temp_prompts(user_id=user_id)
kbds = InlineKeyboardBuilder()
kbds.add(InlineKeyboardButton(
text="⬅️Назад",
callback_data=PageCallBack(
page=3,
page_name='more_about_models'
).pack()
))
if remaining_queries > 0:
# Обрабатываем вопрос с помощью OpenAI GPT
openai_response = await get_model_suggestion_from_openai(message.text)
# Отправляем ответ пользователю
# await message.answer(text=f"Ответ OpenAI: {openai_response}" + f"\nОсталось {remaining_queries-1} запросов.", reply_markup=kbds.adjust(*(1,)).as_markup())
# Уменьшаем количество запросов
if "Ошибка при обращении к OpenAI" not in openai_response:
await message.answer(
text=f"Ответ OpenAI: {openai_response}" + f"\nОсталось {remaining_queries - 1} запросов.",
reply_markup=kbds.adjust(*(1,)).as_markup())
# await decrease_test_queries(user_id)
...
else:
await message.answer(
text=f"Попробуйте еще раз или чуть подождите!")
else:
await message.answer(text="У вас закончились доступные запросы для подбора модели.", reply_markup=kbds.adjust(*(1,)).as_markup())
@user.message(Command(commands=['export_users']))
async def send_csv_to_admin(message: types.Message):
# Генерируем CSV файл
if message.from_user.id in admins:
users = await get_all_users()
# Генерируем CSV файл
with open('data/users.csv', 'w', newline='', encoding='utf-8') as csvfile:
csvwriter = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
csvwriter.writerow(['ID', 'First Name', 'Last Name', 'Username'])
for user in users:
csvwriter.writerow([user.user_id, user.first_name, user.last_name, user.user_name])
# Отправляем CSV файл администратору
csv_file = FSInputFile('data/users.csv') # Обернуть путь к файлу как InputFile
await message.answer_document(csv_file)
@user.message(Command(commands=['send_message_to_all']))
async def send_messages_to_users(message: types.Message, state: FSMContext):
if message.from_user.id in admins:
# Устанавливаем состояние, что бот ждет текст сообщения для рассылки
await state.set_state(SendMessageState.waiting_for_message)
await message.answer("Введите сообщение для рассылки:")
@user.message(SendMessageState.waiting_for_message)
async def get_message_for_users(msg: types.Message, state: FSMContext):
# Получаем текст сообщения для рассылки
text_to_send = msg.text
users = await get_all_users()
# Рассылаем сообщение всем пользователям
for user in users:
if user.user_id == msg.from_user.id:
continue
try:
await msg.bot.send_message(chat_id=user.user_id, text=f'Сообщение от админа:\n{text_to_send}')
except Exception as e:
# Логируем ошибки для недоступных пользователей
print(f"Не удалось отправить сообщение пользователю {user.user_id}: {e}")
await msg.answer("Сообщение успешно отправлено всем пользователям.")
# Очистить состояние после завершения рассылки
await state.clear()
@user.message(~Command(commands=["export_users", 'send_message_to_all'])) # Игнорируем команды
async def chatgpt_chatting(message: types.Message):
user_id = message.from_user.id
db_model = await get_current_model(user_id)
kbds = InlineKeyboardBuilder()
kbds.add(InlineKeyboardButton(
text="Выбрать тариф",
callback_data=PageCallBack(
page=2,
page_name='tarif'
).pack()))
kbds.add(InlineKeyboardButton(
text="⬅️На главную",
callback_data=PageCallBack(
page=0,
page_name='main'
).pack()
))
if db_model is None:
await message.bot.send_message(chat_id=message.from_user.id, text="У вас еще не выбрана модель", reply_markup=kbds.adjust(*(1,)).as_markup())
models = {
'1o' : "o1-preview-2024-09-12",
'1o mini': "o1-mini-2024-09-12",
'4o': "gpt-4o",
'4o mini': "gpt-4o-mini"
}
current_model = models[db_model]
remaining_queries = await get_current_model_tokens(user_id=user_id, name_of_model=db_model)
if remaining_queries > 0:
openai_response = await get_answer_to_question(message.text, current_model)
# Уменьшаем количество запросов
if "Ошибка при обращении к OpenAI" not in openai_response:
await decrease_current_model_tokens(user_id, name_of_model=db_model)
await message.answer(text=f"Ответ OpenAI: {openai_response}")
await message.answer(text=f"Модель: {current_model}\nОсталось {remaining_queries - 1} запросов.",
reply_markup=kbds.adjust(*(1,)).as_markup())
else:
await message.answer(
text=f"{openai_response}")
await message.answer(
text=f"Попробуйте еще раз или вы можете выбрать другую доступную для вас модель!")
else:
await message.answer(text=f"У вас закончились доступные запросы для модели {current_model}. Купите новые токены или выберете другую модель",
reply_markup=kbds.adjust(*(1,)).as_markup())