Skip to content

Commit

Permalink
Merge pull request #49 from F33RNI/next
Browse files Browse the repository at this point in the history
Next
  • Loading branch information
F33RNI authored Sep 9, 2023
2 parents f886c7f + 70813d7 commit 20de3b2
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 57 deletions.
31 changes: 26 additions & 5 deletions BingImageGenModule.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import BotHandler
import UsersHandler
from JSONReaderWriter import load_json
from RequestResponseContainer import RequestResponseContainer


Expand Down Expand Up @@ -60,8 +61,30 @@ def initialize(self, proxy=None) -> None:
logging.warning("Bing ImageGen module disabled in config file!")
raise Exception("Bing ImageGen module disabled in config file!")

# Parse cookies
auth_cookie = ""
auth_cookie_SRCHHPGUSR = ""
try:
cookies = load_json(self.config["bing_imagegen"]["cookies_file"])
if not cookies or len(cookies) < 1:
raise "Error reading bing cookies!"
for cookie in cookies:
if cookie["name"] == "_U":
auth_cookie = cookie["value"]
elif cookie["name"] == "SRCHHPGUSR":
auth_cookie_SRCHHPGUSR = cookie["value"]
if not auth_cookie:
raise "No _U cookie!"
if not auth_cookie_SRCHHPGUSR:
raise "No SRCHHPGUSR cookie!"
except Exception as e:
raise e

# Initialize Bing ImageGen
self._image_generator = ImageGen(self.config["bing_imagegen"]["cookies_file"], quiet=True)
self._image_generator = ImageGen(auth_cookie=auth_cookie,
auth_cookie_SRCHHPGUSR=auth_cookie_SRCHHPGUSR,
quiet=True,
all_cookies=cookies)

# Set proxy
if proxy:
Expand Down Expand Up @@ -99,19 +122,17 @@ def process_request(self, request_response: RequestResponseContainer) -> None:
self.users_handler.save_user(request_response.user)

# Generate images
# TODO: Make it work
logging.info("Requesting images from Bing ImageGen")
response_urls = self._image_generator.get_images(request_response.request)
print(response_urls)

# Check response
if not response_urls or len(response_urls) < 1:
raise Exception("Wrong Bing ImageGen response!")

# TODO: Use all generated images (for now it's the first one)
# Use all generated images
logging.info("Response successfully processed for user {0} ({1})"
.format(request_response.user["user_name"], request_response.user["user_id"]))
request_response.response = response_urls[0]
request_response.response = response_urls

# Exit requested
except KeyboardInterrupt:
Expand Down
152 changes: 119 additions & 33 deletions BotHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from typing import List, Dict

import telegram
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, InputMediaPhoto
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters, CallbackQueryHandler

import LoggingHandler
Expand Down Expand Up @@ -128,8 +128,22 @@ async def send_message_async(config: dict, messages: List[Dict],
lang = UsersHandler.get_key_or_none(request_response.user, "lang", 0)

# Fix empty message
if len(request_response.response.strip()) <= 0 and end:
request_response.response = messages[lang]["empty_message"]
if end:
if not request_response.response \
or (type(request_response.response) == list and len(request_response.response) == 0) \
or (type(request_response.response) == str and len(request_response.response.strip()) <= 0):
request_response.response = messages[lang]["empty_message"]

# Split large response into parts (by index)
if type(request_response.response) == str and len(request_response.response) > 0:
while True:
index_start = request_response.response_part_positions[-1]
response_part_length = len(request_response.response[index_start:-1])
if response_part_length > config["telegram"]["one_message_limit"]:
request_response.response_part_positions\
.append(index_start + config["telegram"]["one_message_limit"])
else:
break

# The last message
if end:
Expand Down Expand Up @@ -180,24 +194,44 @@ async def send_message_async(config: dict, messages: List[Dict],
if (request_response.request_type == RequestResponseContainer.REQUEST_TYPE_DALLE
or request_response.request_type == RequestResponseContainer.REQUEST_TYPE_BING_IMAGEGEN) \
and not request_response.error:
request_response.message_id = (await (telegram.Bot(config["telegram"]["api_key"]).sendPhoto(
chat_id=request_response.user["user_id"],
photo=request_response.response,
reply_to_message_id=request_response
.reply_message_id,
reply_markup=request_response.reply_markup))) \
.message_id
# Single photo
if type(request_response.response) == str:
request_response.message_id = (await (telegram.Bot(config["telegram"]["api_key"]).sendPhoto(
chat_id=request_response.user["user_id"],
photo=request_response.response,
reply_to_message_id=request_response
.reply_message_id,
reply_markup=request_response.reply_markup))) \
.message_id

# Multiple photos (send media group + markup as seperate messages)
else:
# Collect media group
media_group = []
for url in request_response.response:
media_group.append(InputMediaPhoto(media=url))

# Send it
media_group_message_id = (await (telegram.Bot(config["telegram"]["api_key"]).sendMediaGroup(
chat_id=request_response.user["user_id"],
media=media_group,
reply_to_message_id=request_response.reply_message_id)))[0].message_id

# Send reply markup and get message ID
request_response.message_id = await send_reply(config["telegram"]["api_key"],
request_response.user["user_id"],
messages[lang]["media_group_response"]
.format(request_response.request),
media_group_message_id,
markdown=False,
reply_markup=request_response.reply_markup,
edit_message_id=request_response.message_id)

# Send message as text
else:
request_response.message_id = await send_reply(config["telegram"]["api_key"],
request_response.user["user_id"],
request_response.response.strip(),
request_response.reply_message_id,
markdown=True,
reply_markup=request_response.reply_markup,
edit_message_id=request_response.message_id)
await _send_text_async_split(config, request_response, end)

# First or any other message
# First or any other message (text only)
else:
# Get current time
time_current = time.time()
Expand All @@ -209,28 +243,15 @@ async def send_message_async(config: dict, messages: List[Dict],
and (request_response.response_len_last <= 0 or len(request_response.response.strip())
!= request_response.response_len_last):

# Is it first message?
# Generate stop button if it's the first message
if request_response.message_id is None or request_response.message_id < 0:
# Generate stop button
button_stop = InlineKeyboardButton(messages[lang]["button_stop_generating"],
callback_data="{0}_stop_{1}".format(
request_response.request_type,
request_response.reply_message_id))
request_response.reply_markup = InlineKeyboardMarkup(build_menu([button_stop]))

# Add cursor symbol?
response_text = request_response.response.strip()
if config["telegram"]["add_cursor_symbol"]:
response_text += config["telegram"]["cursor_symbol"]

# Send message
request_response.message_id = await send_reply(config["telegram"]["api_key"],
request_response.user["user_id"],
response_text,
request_response.reply_message_id,
markdown=True,
reply_markup=request_response.reply_markup,
edit_message_id=request_response.message_id)
await _send_text_async_split(config, request_response, end)

# Save new data
request_response.response_len_last = len(request_response.response.strip())
Expand All @@ -244,6 +265,71 @@ async def send_message_async(config: dict, messages: List[Dict],
request_response.response_timestamp = time.time()


async def _send_text_async_split(config: dict,
request_response: RequestResponseContainer.RequestResponseContainer,
end=False):
"""
Sends text in multiple messages if needed (must be previously split)
:param config:
:param request_response:
:param end:
:return:
"""
# Send all parts of message
response_part_counter_init = request_response.response_part_counter
while True:
# Get current part of response
response_part_index_start \
= request_response.response_part_positions[request_response.response_part_counter]
response_part_index_stop = -1
if request_response.response_part_counter < len(request_response.response_part_positions) - 1:
response_part_index_stop \
= request_response.response_part_positions[request_response.response_part_counter + 1]
response_part \
= request_response.response[response_part_index_start:response_part_index_stop].strip()

# Get message ID to reply to
reply_to_id = request_response.reply_message_id
if request_response.message_id >= 0 and request_response.response_part_counter > 0:
reply_to_id = request_response.message_id

edit_id = None
# Edit last message if first loop enter
if response_part_counter_init == request_response.response_part_counter:
edit_id = request_response.message_id

# Check if it is not empty
if len(response_part) > 0:
# Send with markup and exit from loop if it's the last part
if response_part_index_stop == -1:
# Add cursor symbol?
if not end and config["telegram"]["add_cursor_symbol"]:
response_part += config["telegram"]["cursor_symbol"]

request_response.message_id = await send_reply(config["telegram"]["api_key"],
request_response.user["user_id"],
response_part,
reply_to_id,
markdown=True,
reply_markup=request_response.reply_markup,
edit_message_id=edit_id)
break
# Send as new message without markup and increment counter
else:
request_response.message_id = await send_reply(config["telegram"]["api_key"],
request_response.user["user_id"],
response_part,
reply_to_id,
markdown=True,
reply_markup=None,
edit_message_id=edit_id)
request_response.response_part_counter += 1

# Exit from loop if no response in current part
else:
break


async def send_reply(api_key: str, chat_id: int, message: str, reply_to_message_id: int | None,
markdown=False, reply_markup=None, edit_message_id=None):
"""
Expand Down
27 changes: 17 additions & 10 deletions QueueHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,16 +675,23 @@ def _collect_data(self, request_response: RequestResponseContainer, log_request=

# Log response
else:
# DALL-E or BingImageGen response without error
if (request_response.request_type == RequestResponseContainer.REQUEST_TYPE_DALLE
or request_response.request_type == RequestResponseContainer.REQUEST_TYPE_BING_IMAGEGEN) \
and not request_response.error:
response = base64.b64encode(requests.get(request_response.response, timeout=120).content) \
.decode("utf-8")

# Text response (ChatGPT, EdgeGPT, Bard)
else:
response = request_response.response
response = "None"
try:
# DALL-E or BingImageGen response without error
if (request_response.request_type == RequestResponseContainer.REQUEST_TYPE_DALLE
or request_response.request_type == RequestResponseContainer.REQUEST_TYPE_BING_IMAGEGEN) \
and not request_response.error:
response_url = request_response.response if type(request_response.response) == str\
else request_response.response[0]
response = base64.b64encode(requests.get(response_url, timeout=120).content) \
.decode("utf-8")

# Text response (ChatGPT, EdgeGPT, Bard)
else:
response = request_response.response
except Exception as e:
logging.warning("Can't parse response for data logging!", exc_info=e)
response = str(response)

# Log response
response_str_to_format = self.config["data_collecting"]["response_format"].replace("\\n", "\n") \
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ You can enable and configure data collection in config in `data_collecting` bloc
## 📝 TODO

- Add some free GPT-4 model
- Make Bing ImageGet work
- Add rate limit
- Add list of commands

----------

Expand Down
4 changes: 4 additions & 0 deletions RequestResponseContainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,9 @@ def __init__(self,
self.processing_start_timestamp = 0.
self.error = False

# Used by BotHandler to split large message into smaller ones (list of indexes of text in response)
self.response_part_positions = [0]
self.response_part_counter = 0

# Unique ID for container to get it from queue (address)
self.id = -1
13 changes: 8 additions & 5 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"edgegpt": true,
"dalle": true,
"bard": true,
"bing_imagegen": false,
"bing_imagegen": true,

"__comment04__": "Default (initial) module for handling user messages (see RequestResponseContainer.py)",
"default_module": 0
Expand Down Expand Up @@ -92,10 +92,10 @@
"timeout_seconds": 120,

"__comment15__": "HOW OFTEN EACH USER CAN SEND REQUESTS TO THIS MODULE (SPECIFY 0 TO REMOVE THE RESTRICTION)",
"user_cooldown_seconds": 600
"user_cooldown_seconds": 120
},

"__comment05__": "BING IMAGEGEN SETTINGS (CURRENTLY NOT WORKING)",
"__comment05__": "BING IMAGEGEN SETTINGS",
"bing_imagegen": {
"__comment01__": "PATH TO COOKIES FILE (JSON) https://github.com/acheong08/EdgeGPT#collect-cookies",
"cookies_file": "EdgeGPT_cookies.json",
Expand All @@ -108,7 +108,7 @@
"timeout_seconds": 120,

"__comment15__": "HOW OFTEN EACH USER CAN SEND REQUESTS TO THIS MODULE (SPECIFY 0 TO REMOVE THE RESTRICTION)",
"user_cooldown_seconds": 0
"user_cooldown_seconds": 120
},

"__comment06__": "BARD SETTINGS",
Expand Down Expand Up @@ -151,7 +151,10 @@
"add_cursor_symbol": true,
"cursor_symbol": "",

"__comment07__": "SET TO true FOR THE BOT TO REPLY TO PLAIN MESSAGES AS WELL AS DIRECT MODULE COMMANDS",
"__comment07__": "IF RESPONSE IS LARGER THAN THIS NUMBER (IN CHARS), IT WILL BE SPLIT INTO MULTIPLE MESSAGES",
"one_message_limit": 3000,

"__comment08__": "SET TO true FOR THE BOT TO REPLY TO PLAIN MESSAGES AS WELL AS DIRECT MODULE COMMANDS",
"reply_to_messages": true
},

Expand Down
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from JSONReaderWriter import load_json

# GPT-Telegramus version
__version__ = "3.2.1"
__version__ = "3.4.0"

# Logging level
LOGGING_LEVEL = logging.INFO
Expand Down
Loading

0 comments on commit 20de3b2

Please sign in to comment.