import re
import time
import shelve
import requests
from datetime import datetime
from aiogram.methods import AnswerGuestQuery, SendPoll
from aiogram.types import InlineQueryResultArticle, InputTextMessageContent, InputRichMessageContent, InputRichMessage, Message
from aiogram.enums import ChatType
from vars import *
from config import *
def is_blocked(user_id):
current_time = time.time()
if user_id and user_id in last_command_time:
time_diff = current_time - last_command_time[user_id][0]
if user_id in last_error_time:
time_error_diff = current_time - last_error_time[user_id]
else:
last_error_time[user_id] = current_time
time_error_diff = 1984
if time_diff < 3:
alo = "π« *ΡΠ°ΠΉΠ» Π½Π΅ Π²ΠΎΡΡΠ».* Ρ
Π²Π°ΡΠΈΡ ΡΠ°ΠΊ Π±ΡΡΡΡΠΎ ΡΠ»Π°ΡΡ ΡΠ²ΠΎΠΈ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ.\n" \
f"ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ {round(3 - time_diff, 3)} ΡΠ΅ΠΊΡΠ½Π΄, Π±ΡΠ°Ρπ‘π‘"
elif last_command_time[user_id][1] and time_diff < 5:
alo = "π« *ΡΠ°ΠΉΠ» Π½Π΅ Π²ΠΎΡΡΠ».* Ρ Π΅ΡΡ Π½Π΅ ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π» ΠΏΡΠΎΡΠ»ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅.\n" \
f"ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ {round(10 - time_diff, 3)} ΡΠ΅ΠΊΡΠ½Π΄, ΡΡΠΎΠ±Ρ Ρ Π·Π°ΠΊΡΡΠ» Π³Π»Π°Π·Π° " \
"Π½Π° ΡΡΠΎ da."
elif len(last_command_time[user_id][2]) > 1 and time_diff > 5:
last_command_time[user_id] = [current_time, False, []]
return "", False
elif len(last_command_time[user_id][2]) > 1:
alo = "π« *ΡΠ°ΠΉΠ» Π½Π΅ Π²ΠΎΡΡΠ».* Ρ
Π²Π°ΡΠΈΡ ΡΠ°ΠΊ Π±ΡΡΡΡΠΎ ΡΠ»Π°ΡΡ ΡΠ²ΠΎΠΈ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ."
else:
return "", False
if time_error_diff < 2:
return "", True
else:
last_error_time[user_id] = current_time
return alo, True
return "", False
def is_replied_bot(message, is_channel, user_text, config=None):
if message.chat.type in [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL]:
if not is_channel:
is_reply_to_bot = (
message.reply_to_message
and message.reply_to_message.from_user
and message.reply_to_message.from_user.is_bot
and message.reply_to_message.from_user.username == BOT_USERNAME
)
if config:
if config.get("call") == "da":
mentions_bot = any(
user_text.lower().split(" ", 1)[0] == call for call in BOT_CALLS
)
for call in BOT_CALLS:
if call.startswith("@"):
if call.lower() in user_text.lower():
mentions_bot = True
else:
mentions_bot = False
else:
mentions_bot = any(
user_text.lower().startswith(call.lower()) for call in BOT_CALLS
)
for call in BOT_CALLS:
if call.startswith("@"):
if call.lower() in user_text.lower():
mentions_bot = True
if not (is_reply_to_bot or mentions_bot):
return False
return True
async def g_answer(
message,
text,
title="da",
id="1",
parse_mode="Markdown",
reply_markup=None,
user_id=None
):
input_message_content = InputTextMessageContent(
message_text=text,
parse_mode=parse_mode
)
if user_id:
config = get_user_config(user_id)
if config["markdown"] == "new":
input_message_content=InputRichMessageContent(
rich_message=InputRichMessage(markdown=text)
)
return await message.answer_guest_query(
result=InlineQueryResultArticle(
id=id,
reply_markup=reply_markup,
title=title,
input_message_content=input_message_content
)
)
async def answer_poll(
data,
message,
question,
options,
is_anonymous=True,
poll_type="regular",
allows_multiple_answers=False,
correct_option_id=None,
user_id=None
):
return await data["bot"](
SendPoll(
chat_id=user_id,
question=question,
options=options,
is_anonymous=is_anonymous,
type=poll_type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
)
)
def send_to_vosk(audio):
files = {
"audio": (
"voice.ogg",
audio,
"audio/ogg"
)
}
r = requests.post(
VOSK_API,
files=files,
timeout=15
)
return r.json()
async def mans(message, text):
if message.guest_query_id:
return await message.answer_guest_query(
result=InlineQueryResultArticle(
id=1,
reply_markup=None,
title="da",
input_message_content=InputTextMessageContent(
message_text=text,
parse_mode="Markdown"
)
)
)
else:
return await message.reply(text)
def graph_emoji(status):
match status:
case "done":
return "β
"
case "error":
return "π«"
case "make":
return "π"
case "wait":
return "β³"
case _:
return "π₯Ί"
def make_graph(message, process):
text = ""
replied = message.reply_to_message or None
user_id = message.from_user.id
config = get_user_config(user_id)
im_model = IMAGE_MODEL.split("*", 1)
model = config["model"].split("*", 1)
photo_a = process.get("photo_a", None)
photo = process.get("photo", None)
stt = process.get("stt", None)
t = process.get("text", None)
if photo_a:
text += f"{graph_emoji(photo_a)} Π°Π½Π°Π»ΠΈΠ· ΡΠΎΡΠΎ (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if photo:
text += f"{graph_emoji(photo)} Π°Π½Π°Π»ΠΈΠ· ΡΠΎΡΠΎ\n"
if stt:
text += f"{graph_emoji(stt)} stt (Π³ΠΎΠ»ΠΎΡ -> ΡΠ΅ΠΊΡΡ)\n"
text += f"{graph_emoji(t)} Π·Π°ΠΏΡΠΎΡ `{model[1]}` (`{model[0]}`)\n"
if replied and replied.document:
text += f"β³ {replied.document.file_size} ΡΠ°ΠΉΠ» (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if message.document:
text += f"β³ {message.document.file_size} ΡΠ°ΠΉΠ»\n"
if replied and replied.photo:
text += "β³ ΡΠΎΡΠΎ (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if message.photo:
text += "β³ ΡΠΎΡΠΎ\n"
if replied and replied.location:
text += "β³ Π³Π΅ΠΎΠ»ΠΎΠΊΠ°ΡΠΈΡ (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if message.location:
text += "β³ Π³Π΅ΠΎΠ»ΠΎΠΊΠ°ΡΠΈΡ\n"
if replied and replied.poll:
text += "β³ ΠΎΠΏΡΠΎΡ (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if message.poll:
text += "β³ ΠΎΠΏΡΠΎΡ\n"
if replied and replied.voice:
text += "β³ Π³ΠΎΠ»ΠΎΡΠΎΠ²ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ (Π² ΠΎΡΠ²Π΅ΡΠ΅)\n"
if message.voice:
text += "β³ Π³ΠΎΠ»ΠΎΡΠΎΠ²ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅\n"
if replied and replied.text:
text += f"β³ {len(replied.text)} ΡΠ΅ΠΊΡΡ Π² ΠΎΡΠ²Π΅ΡΠ΅\n"
return text
def clean_tail_repeats(text: str, max_repeat: int = 10):
if not text:
return text, 0
original_length = len(text)
cleaned = text
pattern = rf"(.)\1{{{max_repeat},}}$"
def limit_repeats(match):
char = match.group(1)
return char * max_repeat
cleaned = re.sub(pattern, limit_repeats, cleaned)
pattern_space = rf"((\S)\s+)\2{{{max_repeat},}}$"
cleaned = re.sub(
pattern_space,
lambda m: (m.group(2) + " ") * min(max_repeat, len(m.group(1))),
cleaned,
)
words = cleaned.split()
if len(words) >= 2:
for i in range(1, min(len(words), 10)):
if all(words[-j] == words[-j - 1] for j in range(i)):
unique_words = words[: -(i + 1)]
cleaned = " ".join(unique_words + [words[-1]])
break
removed_count = original_length - len(cleaned)
cleaned = re.sub(r" +", " ", cleaned)
cleaned = cleaned.strip()
return cleaned, removed_count
def get_key(provider, model_full):
prov = PROVIDERS.get(provider, {})
key = prov.get("key", "")
if isinstance(key, list):
parts = model_full.split("*")
if len(parts) >= 3:
try:
idx = int(parts[2]) - 1
except ValueError:
return key[0]
if 0 <= idx < len(key):
return key[idx]
return key[0]
return key
_expanded_auto_models = None
def expand_auto_models():
global _expanded_auto_models
if _expanded_auto_models is not None:
return _expanded_auto_models
result = []
for entry in AUTO_MODELS:
parts = entry.split("*", 2)
if len(parts) < 2:
continue
provider = parts[0]
model = parts[1]
suffix = parts[2] if len(parts) >= 3 else None
prov_key = PROVIDERS.get(provider, {}).get("key", "")
if isinstance(prov_key, list) and not suffix:
for i in range(len(prov_key)):
result.append(f"{provider}*{model}*{i + 1}")
else:
result.append(entry)
_expanded_auto_models = result
return result
def parse_response(text: str):
if "connection error." in text:
return {
"type": "connection",
"message": "ΠΎΡΠΈΠ±ΠΊΠ° ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΡ. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° Π² Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ
ΡΠ·Π±Π΅ΠΊΠ³ΠΏΡ.",
}
elif "model quota exceeded" in text:
return {
"type": "quota",
"message": "Π»ΠΈΠΌΠΈΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ² Π·Π°ΠΊΠΎΠ½ΡΠΈΠ»ΡΡ. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif "tier capacity exceeded." in text:
return {"type": "tier", "message": "ΠΏΠΎΠΏΡΠΎΠ±ΡΠΉ Π΅ΡΡ ΡΠ°Π·!"}
elif "internal server" in text:
return {
"type": "int",
"message": "ΠΏΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΎΡΠΈΠ±ΠΊΠ° Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ°. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° Π² Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ
ΡΠ·Π±Π΅ΠΊΠ³ΠΏΡ.",
}
elif "(incomplete chunked read)" in text:
return {
"type": "incomplete",
"message": "ΡΠ΅ΡΠ²Π΅Ρ ΠΏΠ΅ΡΡΡ
ΠΈ ΠΎΠ±ΠΎΡΠ²Π°Π» ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° Π² Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ
ΡΠ·Π±Π΅ΠΊΠ³ΠΏΡ.",
}
elif "provider error" in text:
return {
"type": "provider",
"message": "Π²ΡΠ°Ρ ΠΎΡΠΈΠ±ΠΊΠ° Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° ΠΌΠΎΠ΄Π΅Π»ΠΈ. ΡΠΌΠ΅Π½ΠΈ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° ΠΈΠ»ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif "rate limit" in text:
return {
"type": "quota",
"message": "Π»ΠΈΠΌΠΈΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ² Π·Π°ΠΊΠΎΠ½ΡΠΈΠ»ΡΡ Ρ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° Π²ΡΠ°Ρ. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif "response payload is not completed" in text or "not enough data to satisfy" in text or "server disconnected" in text or "connection reset" in text or "serverdisconnectederror" in text:
return {
"type": "incomplete",
"message": "ΡΠ΅ΡΠ²Π΅Ρ ΠΏΠ΅ΡΡΡ
ΠΈ ΠΎΠ±ΠΎΡΠ²Π°Π» ΠΎΡΠ²Π΅Ρ Π½Π° ΡΠ΅ΡΠ΅Π΄ΠΈΠ½Π΅. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif "timeout" in text or "timed out" in text:
return {
"type": "timeout",
"message": "ΡΠ΅ΡΠ²Π΅Ρ Π΄ΡΠΌΠ°Π» ΡΠ»ΠΈΡΠΊΠΎΠΌ Π΄ΠΎΠ»Π³ΠΎ ΠΈ ΡΠΌΠ΅Ρ. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif "not found" in text or " 404" in text or "404 " in text or "no such model" in text or "does not exist" in text:
return {
"type": "notfound",
"message": "ΠΌΠΎΠ΄Π΅Π»Ρ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π° Ρ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ°. ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ Π² Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ
.",
}
elif "forbidden" in text or "unauthorized" in text or " 403" in text or "403 " in text or " 401" in text or "401 " in text or "invalid api key" in text or "incorrect api key" in text:
return {
"type": "key",
"message": "ΠΊΠ»ΡΡ ΠΈΠ»ΠΈ Π΄ΠΎΡΡΡΠΏ ΠΊ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΡ ΡΠ΄ΠΎΡ
. ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ ΠΈΠ»ΠΈ Π½Π°ΠΏΠΈΡΠΈ Ρ
ΠΎΡΡΠ΅ΡΡ.",
}
elif " 429" in text or "429 " in text or "exhausted" in text or "quota" in text:
return {
"type": "quota",
"message": "Π»ΠΈΠΌΠΈΡ Π·Π°ΠΏΡΠΎΡΠΎΠ² Ρ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ° Π·Π°ΠΊΠΎΠ½ΡΠΈΠ»ΡΡ. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
elif " 500" in text or "500 " in text or " 502" in text or "502 " in text or " 503" in text or "503 " in text or "bad gateway" in text:
return {
"type": "int",
"message": "ΠΎΡΠΈΠ±ΠΊΠ° Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ°. ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈ ΠΈΠ»ΠΈ ΡΠΌΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»Ρ.",
}
else:
return {
"type": "unknown",
"message": f"ΠΏΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΊΠ°ΠΊΠ°Ρ-ΡΠΎ ΠΎΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ... {text}",
}
def galockinator(text):
for _ in range(random.randint(1, 3)):
if random.random() < 0.3:
text += "βοΈ"
else:
text += "β
"
return text
def remove_think_tags(text):
result = re.sub(r"