-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
217 lines (184 loc) · 9.16 KB
/
main.py
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
# -*- coding: utf-8 -*-
from aiogram.types import ReplyKeyboardRemove, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.builtin import CommandStart
from aiogram.dispatcher.filters import BoundFilter
from aiogram.dispatcher.filters import Command
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher import Dispatcher
from aiogram.utils import executor
from aiogram import Bot, types
import asyncio, sqlite3, openai, time, logging, re
#################################################################################################################################
storage = MemoryStorage()
bot = Bot(token=bot_token)
dp = Dispatcher(bot, storage=storage)
logging.basicConfig(format=u'%(filename)s [LINE:%(lineno)d] #%(levelname)-8s [%(asctime)s] %(message)s', level=logging.INFO,)
openai.api_key = openai_api_key
#################################################################################################################################
class openai_plowsidee:
def __init__(self):
self.alive = True
self.response = ''
async def create_conversation(self, question, conf=[]):
conf.append({"role": "user", "content": question})
last_resp = ''
async for resp in await openai.ChatCompletion.acreate(model='gpt-3.5-turbo', messages=conf, max_tokens=2048, stream=True):
if resp.choices[0].finish_reason != None: self.alive=False;break
try:
if resp.choices[0].delta.content != last_resp:
self.response+=str(resp.choices[0].delta.content)
last_resp = resp.choices[0].delta.content
except:pass
self.alive=False
con = sqlite3.connect('db.db')
cur = con.cursor()
cur.execute('''CREATE TABLE IF NOT EXISTS users(
id INTEGER,
username TEXT,
first_name TEXT,
question_num INTEGER DEFAULT (0)
)''')
cur.execute('''CREATE TABLE IF NOT EXISTS conversations(
id INTEGER,
uid INTEGER,
question TEXT,
create_date INT,
answer TEXT,
is_show BOOL DEFAULT (True)
)''')
# Hi message
@dp.message_handler(CommandStart())
async def start(message: types.Message):
user_db = (cur.execute(f'SELECT * FROM users WHERE id = {message.from_user.id}')).fetchone()
temp=message.from_user.first_name.replace('"','""')
if user_db is None:
cur.execute(f'INSERT INTO users VALUES ({message.from_user.id}, "{message.from_user.username if message.from_user.username else "no_username"}","{temp}", 0)')
elif user_db[2] != message.from_user.first_name:
cur.execute(f'UPDATE users SET first_name = "{temp}" WHERE id = {message.from_user.id}')
elif user_db[1] != message.from_user.username:
cur.execute(f'UPDATE users SET username = "{message.from_user.username}" WHERE id = {message.from_user.id}')
con.commit()
await message.answer('''<b>Привет!</b>
Этот бот открывает вам доступ к продуктам OpenAI, таким как ChatGPT, для создания текста и изображений (В будущем).
⚡️Бот использует <b>ту же модель, что и сайт ChatGPT: gpt-3.5-turbo.</b>
<b>Чатбот умеет:</b>
1. <i>Писать и редактировать тексты</i>
2. <i>Переводить с любого языка на любой</i>
3. <i>Писать и редактировать код</i>
4. <i>Отвечать на вопросы</i>
Вы можете общаться с ботом, как с живым собеседником, задавая вопросы на любом языке. Обратите внимание, что иногда бот придумывает факты, а также обладает ограниченными знаниями о событиях после 2021 года.
✉️ Чтобы получить <b>текстовый ответ</b>, просто напишите в чат ваш вопрос.
🔄 Чтобы удалить <b>контекст диалога</b> используйте команду /deletecontext.''', parse_mode=types.ParseMode.HTML)
# Delete last context
@dp.message_handler(commands=['deletecontext'])
async def deletecontext(message: types.Message):
cur.execute(f"UPDATE conversations SET is_show = False WHERE uid = {message.from_user.id}")
con.commit()
await message.answer('<b>Контекст удален. По умолчанию бот в ответе учитывает все ваши предыдущие вопросы/сообщения и свои ответы на них.</b>', parse_mode=types.ParseMode.HTML)
# get datebase backup
@dp.message_handler(commands=['db'])
async def db(message: types.Message):
if message.from_user.id in admin_id: await message.answer_document(open('db.db','rb'))
# Main handler
@dp.message_handler(content_types=['text'])
async def get_question(message: types.Message):
user_db = (cur.execute(f'SELECT * FROM users WHERE id = {message.from_user.id}')).fetchone()
temp=message.from_user.first_name.replace('"','""')
if user_db is None:
cur.execute(f'INSERT INTO users VALUES ({message.from_user.id}, "{message.from_user.username if message.from_user.username else "no_username"}","{temp}", 0)')
elif user_db[2] != message.from_user.first_name:
cur.execute(f'UPDATE users SET first_name = "{temp}" WHERE id = {message.from_user.id}')
elif user_db[1] != message.from_user.username:
cur.execute(f'UPDATE users SET username = "{message.from_user.username}" WHERE id = {message.from_user.id}')
con.commit()
conversation = get_conversation(message.from_user.id)
conf = [{'role':'user','content':x[2]} for x in conversation]
text = message.text.replace("'","''")
count = len((cur.execute(f'SELECT * FROM conversations WHERE uid = {message.from_user.id}')).fetchall())
logging.info(f'User: [{message.from_user.id}|{"@"+message.from_user.username if message.from_user.username else "no_username"}|{message.from_user.first_name}|{count}]')
await bot.send_chat_action(chat_id=message.chat.id, action="typing")
op = openai_plowsidee()
asyncio.get_event_loop().create_task(op.create_conversation(message.text, conf))
last_resp = 0
answer = ''
message_ = None
while op.alive:
if len(op.response) - last_resp > 220:
answer = op.response
last_resp = len(answer)
if message_ is None:
try:message_ = await message.answer(answer)
except:pass
else:
try:await message_.edit_text(answer)
except:pass
await asyncio.sleep(.5)
answer = op.response
temp=answer.replace("'","''")
cur.execute(f"INSERT INTO conversations(id,uid,question,create_date,answer) VALUES ({count},{message.from_user.id}, '{text}', {int(time.time())}, '{temp}')")
cur.execute(f'UPDATE users SET question_num = {count+1} WHERE id = {message.from_user.id}')
con.commit()
if "```" in answer:
def kb_temp(id, uid):
keyboard = InlineKeyboardMarkup()
s={'Получить код':f'util:get_code:{id}:{uid}'}
for x in s: keyboard.insert(InlineKeyboardButton(x,callback_data=s[x]))
return keyboard
if message_ is None:
message_ = await message.answer(answer, reply_markup=kb_temp(count,message.from_user.id))
else: await message_.edit_text(answer, reply_markup=kb_temp(count,message.from_user.id))
else:
if message_ is None:
message_ = await message.answer(answer)
else:
try:await message_.edit_text(answer)
except:pass
# callback handler [get code from text]
@dp.callback_query_handler(text_startswith='util')
async def util(call: types.CallbackQuery):
cd = call.data.split(':')
if cd[1] == 'get_code':
gg=cur.execute(f'SELECT answer FROM conversations WHERE id = {int(cd[2])} AND uid = {int(cd[3])}')
s=gg.fetchone()[0]
if s == '' or s is None:
await call.answer('Error: message is empty',show_alert=True)
return
last=0
br=len(re.findall("```",s))
text=[]
num = 0
while True:
try:
num+=1
_1=s.index("```",last+3) + 3
_2=s.index("```", _1)
if len(text) * 2 >= br:
break
last = _2
text.append(f'<b>Code №{num}:</b>\n<code>{s[_1:_2].strip()}</code>')
except Exception as error:
print(error)
break
await call.message.answer('\n\n'.join(text), parse_mode=types.ParseMode.HTML)
# Get active context from db
def get_conversation(uid):
return cur.execute(f'SELECT * FROM conversations WHERE uid = {uid} AND is_show = True').fetchall()
# Get answer from openai
async def get_answer(question, conf=[]):
conf.append({"role": "user", "content": question})
response = await openai.ChatCompletion.acreate(model='gpt-3.5-turbo', messages=conf, max_tokens=2048, temperature=0.7)
return response.choices[0].message['content']
#################################################################################################################################
async def on_startup(dp):
global bot_info
bot_info=await bot.get_me()
async def set_default_commands(dp):
await dp.bot.set_my_commands([types.BotCommand("start", "Запустить бота"),types.BotCommand("deletecontext", "Удалить контекст диалога")])
await set_default_commands(dp)
if __name__ == '__main__':
try: executor.start_polling(dp, on_startup=on_startup)
except Exception as error:
print(error)
logging.critical('Неверный токен бота! | Wrond Telegram bot token!')