diff options
| author | huker667 <huker@tuta.io> | 2026-08-07 23:03:12 +0300 |
|---|---|---|
| committer | huker667 <huker@tuta.io> | 2026-08-07 23:03:12 +0300 |
| commit | 891131b88e2b1684a453a0b9ab9291b97331809e (patch) | |
| tree | 240e23daaa5f17c85e8173cf8fe4f29b6074dca7 | |
| parent | ca0f5bf3deed8bbc82a79834a9419233b559ce14 (diff) | |
| download | uzbekgpt-891131b88e2b1684a453a0b9ab9291b97331809e.tar.gz uzbekgpt-891131b88e2b1684a453a0b9ab9291b97331809e.tar.bz2 uzbekgpt-891131b88e2b1684a453a0b9ab9291b97331809e.zip | |
фикс я хуй знает много чего я добавил
| -rw-r--r-- | LICENSE | 41 | ||||
| -rw-r--r-- | ai.py | 104 | ||||
| -rw-r--r-- | callbacks.py | 110 | ||||
| -rw-r--r-- | commands.py | 18 | ||||
| -rw-r--r-- | config_def.py | 46 | ||||
| -rw-r--r-- | helpers.py | 293 | ||||
| -rw-r--r-- | input_msg.py | 156 | ||||
| -rw-r--r-- | main.py | 270 | ||||
| -rw-r--r-- | requirements.txt | 1 | ||||
| -rw-r--r-- | supergenerator.py | 383 | ||||
| -rw-r--r-- | vars.py | 5 |
11 files changed, 850 insertions, 577 deletions
@@ -1,12 +1,33 @@ -Copyright 2025 Den +Open Plov License Version 1 (OPLv1) -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. +Permission is granted for free use, copying, modification, and +distribution of this software for non-commercial purposes, +provided that this license notice is retained. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. +Any derivative works and modifications must be distributed under +this same license with open source code. + +Closing the source code or distribution under a proprietary +license is prohibited. + +Distribution of compiled (binary) versions of this software +without publicly available source code from which the software was +built is prohibited. + +Code under this license may only be combined with code under +licenses that require maintaining open source code. + +Combining with code under licenses that permit closing source code +or unrestricted commercial use is prohibited. + +When combining with code under other copyleft licenses, the +resulting work must comply with the requirements of both licenses. + +Project dependencies are not subject to the requirements of this +license and may be used according to their own terms. This license +applies only to the original project code and its derivative +works. + +The software is provided "as is", without any warranties. The +copyright holder is not liable for any damages arising from the +use of the software. @@ -0,0 +1,104 @@ +import aiohttp +import asyncio +import json +import gconfig + +try: + from config import * +except: + gconfig.copy_config() +finally: + from config import * + +async def make_request(url, headers, payload): + async with aiohttp.ClientSession(headers=headers) as session: + async with session.post(url, json=payload) as response: + if payload.get("stream") == True: + async for line in response.content: + line = line.decode("utf-8").strip() + if line.startswith("data:"): + data = line[5:].strip() + if data == "DONE": + break + else: + # data = await response.text() + yield data + else: + response_data = b"" + async for chunk in response.content.iter_chunks(): + response_data += chunk[0] + yield response_data.decode() + +async def completions( + url, + api_key, + model, + messages, + stream=False, + max_tokens=MAX_TOKENS, + extra=None +): + print(url) + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json" + } + + payload = { + "messages": messages, + "model": model, + "stream": stream, + "max_tokens": max_tokens, + } + + if extra: + payload = payload | extra + + if stream: + async for data in make_request(url+"/chat/completions", headers, payload): + try: + yield json.loads(data) + except: + yield data + else: + async for data in make_request(url+"/chat/completions", headers, payload): + try: + yield json.loads(data) + except: + yield data + +async def responses( + url, + api_key, + model, + input, + stream=False, + max_tokens=MAX_TOKENS, + extra=None +): + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json" + } + payload = { + "model": model, + "input": input, + "stream": stream, + "max_tokens": max_tokens, + } + if extra: + payload = payload | extra + + if stream: + async for data in make_request(url+"/chat/completions", headers, payload): + try: + yield json.loads(data) + except: + yield data + else: + async for data in make_request(url+"/chat/completions", headers, payload): + try: + yield json.loads(data) + except: + yield data diff --git a/callbacks.py b/callbacks.py index 1304d7e..2182d45 100644 --- a/callbacks.py +++ b/callbacks.py @@ -860,114 +860,26 @@ async def settings_callback(callback: CallbackQuery): await settings_handler(callback) -@router.callback_query(F.data.startswith("set_stream%")) -async def set_stream_callback(callback: CallbackQuery): +@router.callback_query(F.data.startswith("set%")) +async def set_setting_callback(callback: CallbackQuery): current_user_id = str(callback.from_user.id) - data = callback.data.split("%", 2) - user_id = data[1] - if user_id != current_user_id: - await callback.answer("нет, не трогай это не твое") - return - - new_status = callback.data.split("%")[2] - - config = get_user_config(user_id) - if new_status == "native" or new_status == "edit": - set_user_config( - user_id, - config.get("model"), - new_status, - config.get("call"), - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config.get("prompts"), - ) - else: - set_user_config( - user_id, - config.get("model"), - "none", - config.get("call"), - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config.get("prompts"), - ) - await settings_handler(callback) - - -@router.callback_query(F.data.startswith("set_call%")) -async def set_call_callback(callback: CallbackQuery): - current_user_id = str(callback.from_user.id) - data = callback.data.split("%", 2) - user_id = data[1] - if user_id != current_user_id: - await callback.answer("нет, не трогай это не твое") - return - - new_status = callback.data.split("%")[2] - - config = get_user_config(user_id) - set_user_config( - user_id, - config.get("model"), - config.get("stream"), - new_status, - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config.get("prompts") - ) - await settings_handler(callback) - - -@router.callback_query(F.data.startswith("set_notify%")) -async def set_notify_callback(callback: CallbackQuery): - current_user_id = str(callback.from_user.id) - data = callback.data.split("%", 2) - user_id = data[1] + data = callback.data.split("%", 3) + user_id = data[2] if user_id != current_user_id: await callback.answer("нет, не трогай это не твое") return - new_status = callback.data.split("%")[2] + new_status = callback.data.split("%")[3] config = get_user_config(user_id) - set_user_config( - user_id, - config.get("model"), - config.get("stream"), - config.get("call"), - config.get("prompt"), - new_status, - config.get("markdown"), - config.get("prompts") - ) - await settings_handler(callback) - -@router.callback_query(F.data.startswith("set_markdown%")) -async def set_markdown_callback(callback: CallbackQuery): - current_user_id = str(callback.from_user.id) - data = callback.data.split("%", 2) - user_id = data[1] - if user_id != current_user_id: - await callback.answer("нет, не трогай это не твое") - return - - new_status = data[2] - - config = get_user_config(user_id) - set_user_config( + alo = { + data[1]: new_status + } + + set_user_setting( user_id, - config.get("model"), - config.get("stream"), - config.get("call"), - config.get("prompt"), - config.get("notify"), - new_status, - config.get("prompts") + **alo ) await settings_handler(callback) diff --git a/commands.py b/commands.py index 32bac3c..4811b4a 100644 --- a/commands.py +++ b/commands.py @@ -27,6 +27,8 @@ from collections import Counter from colors import * from config import * from statistics import * +from vars import * +from helpers import * from supergenerator import * router = Router() @@ -69,7 +71,7 @@ async def stats_handler(message: Message): top_models = models.most_common(5) top_streams = streams.most_common(2) - top_prompts = prompts.most_common(5) + top_prompts = prompts.most_common(10) text = [ "✅ *общая статистика*", @@ -85,8 +87,8 @@ async def stats_handler(message: Message): *(f"- `{s}`: {c}" for s, c in top_streams), "👀топ режимов вызова:", *(f"- `{c}`: {n}" for c, n in calls.most_common()), - "📝топ 5 промптов:", - *(f"- `{c}`: {n}" for c, n in prompts.most_common()), + "📝топ 10 промптов:", + *(f"- `{c}`: {n}" for c, n in top_prompts.most_common()), ] await message.reply("\n".join(text)) @@ -389,7 +391,7 @@ async def prompt_handler(message: Message): config = get_user_config(user_id) system_prompt_name = config["prompt"] if system_prompt_name in SYSTEM_PROMPTS: - system_prompt = SYSTEM_PROMPTS[system_prompt_name] + system_prompt = SYSTEM_PROMPTS[system_prompt_name]["text"] else: await message.reply( f"🤝 произошла ошибка при отображении промпта `{system_prompt_name}`\n*для фото*: ```prompt\n{IMAGE_PROMPT}```изменить системный промпт узбекгпт пока что нельзя." @@ -480,21 +482,21 @@ async def settings_handler(event: Union[Message, CallbackQuery]): [ InlineKeyboardButton( text=f"стрим: {stream_status}", - callback_data=f"set_stream%{user_id}%{stream_cb}", + callback_data=f"set%stream%{user_id}%{stream_cb}", ), InlineKeyboardButton( text=f"отклик: {call_status}", - callback_data=f"set_call%{user_id}%{call_cb}", + callback_data=f"set%call%{user_id}%{call_cb}", ) ], [ InlineKeyboardButton( text=f"рассылка: {notify_status}", - callback_data=f"set_notify%{user_id}%{notify_cb}", + callback_data=f"set%notify%{user_id}%{notify_cb}", ), InlineKeyboardButton( text=f"маркдаун: {markdown_status}", - callback_data=f"set_markdown%{user_id}%{markdown_cb}", + callback_data=f"set%markdown%{user_id}%{markdown_cb}", ), ], diff --git a/config_def.py b/config_def.py index 10e5ec7..4702c57 100644 --- a/config_def.py +++ b/config_def.py @@ -4,39 +4,57 @@ from dotenv import load_dotenv load_dotenv() -ADMIN_ID = 8243488179 +# айди аккаунта админа для команд /reset /broadcast /clean и так далее +ADMIN_ID = 8935141038 # поставь "" пустой da если хочешь отключить поддержку голосовых VOSK_API = "http://127.0.0.1:8080/stt" +# сколько сообщений хранить в контексте MAX_CONTEXT = 7 -MAX_PROMPT = 4000 -MAX_TOKENS = 9000 +# максимальное количество символов в промпте +файлы +MAX_PROMPT = 16000 +# макс токены генерация +MAX_TOKENS = 4000 +# макс символы (только в режиме стрима работает мне лень фиксить) +MAX_SYMBOLS = 13400 +# макс количество кастомных промптов MAX_PROMPTS = 8 +# каждые n (400) символов обновлять стриминг поток +STREAMING_SPLIT_SYMBOLS = 400 + +# не важно BEN_IDS = [-1002147940521, -1001834656942, -1003142512395] ABEN_IDS = [-1002147940521, -1001834656942, -1003142512395] REPORN_IDS = [-1002147940521, -1002775610996, -1001834656942, -1003142512395] +# юз бота без @ BOT_USERNAME = "UzbekGPTTestBot" +# на что бот откликается BOT_CALLS = ["узбек", "uzbek", f"@{BOT_USERNAME}"] +# дефолт настройки для новых юзеров DEFAULT_MODEL = "ollama*gemma4:31b-cloud" -IMAGE_MODEL = "ollama*gemma3:27b-cloud" DEFAULT_STREAM = "none" DEFAULT_CALL = "da" DEFAULT_PROMPT = "standart" DEFAULT_NOTIFY = "da" -# поставь DEFAULT_MARKDOWN на "" если хочешь спросить пользователя что он хочет при первом соо da. -DEFAULT_MARKDOWN = "old" +DEFAULT_MARKDOWN = "old" + +# модель которая умеет принимать картинки очень важно +IMAGE_MODEL = "ollama*gemma3:27b-cloud" +# я забыл если честно SHOW_ACC_MSG = True +# можно отключить некоторые команды SETTINGS_COMMAND = True CLEAR_COMMAND = True PROMPT_COMMAND = True CONFIG_COMMAND = True +# /settings -> о боте ABOUT_BOT = ( "✅ *об узбекгпт* ✅\n" "- создал @zsh69 (хукер667)\n" @@ -45,8 +63,10 @@ ABOUT_BOT = ( "- подпешис: t.me/hukerass" ) -DONATE_LINK = "" +# /settings -> донат, на самом деле можно вставить любой текст а не ссылку +DONATE_LINK = "https://t.me/send?start=IVRLB58MrhCp" +# провайдеры ваши хз PROVIDERS = { "ollama": { "name": "оллама", @@ -68,14 +88,20 @@ PROVIDERS = { # }, } +# какие модели есть и настройки (все настройки ищи в коде) +# - например тут vision ты указываешь умеет ли эта модель смотреть фото. +# если нет, то модель в IMAGE_MODEL будет генерить анализ по фото для +# твоей модели. +# если да, то модель будет напрямую смотреть фото в messages MODELS = { "ollama": { - "gemma3:27b-cloud": {"n_tok": 7, "e_tok": 15, "vision": True}, - "gemma4:31b-cloud": {"n_tok": 30, "e_tok": 50, "vision": True}, + "gemma3:27b-cloud": {"vision": False}, + "gemma4:31b-cloud": {"vision": True}, }, "krutoiapi": { - "da": {"n_tok": 30, "e_tok": 50, "vision": False}, + "claude-mythos-5": {"vision": False}, }, } +# АХУЕТЬ ТОКЕН!! API_TOKEN = os.getenv("API_TOKEN") @@ -1,11 +1,14 @@ +import re import time +import shelve import requests from aiogram.methods import AnswerGuestQuery, SendPoll from aiogram.types import InlineQueryResultArticle, InputTextMessageContent, InputRichMessageContent, InputRichMessage, Message from aiogram.enums import ChatType -from supergenerator import * +from vars import * +from config import * def is_blocked(user_id): @@ -162,3 +165,291 @@ async def mans(message, text): 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 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": "лимит токенов закончился у провайдера врат. подожди или смени модель.", + } + 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"<think>.*?</think>", "", text, flags=re.DOTALL) + result = re.sub(r"<thought>.*?</thought>", "", text, flags=re.DOTALL) + return result + + +def get_all_users(only_notify=False): + with shelve.open("users") as db: + return {k: db[k] for k in db.keys() if not only_notify or db[k].get("notify") == "da"} + + +def get_all_user_ids(only_notify=False): + ids = [] + with shelve.open("users") as db: + for user_id in db.keys(): + if only_notify and db[user_id].get("notify") != "da": + continue + try: + ids.append(int(user_id)) + except ValueError: + pass + return ids + + +def set_user_config( + user_id, + model_name, + stream=DEFAULT_STREAM, + call=DEFAULT_CALL, + prompt=DEFAULT_PROMPT, + notify=DEFAULT_NOTIFY, + markdown=DEFAULT_MARKDOWN, + prompts={}, +): + with shelve.open("users") as db: + db[str(user_id)] = { + "model": model_name, + "stream": stream, + "call": call, + "prompt": prompt, + "notify": notify, + "markdown": markdown, + "prompts": prompts, + } + + + +def set_user_setting( + user_id, + model=None, + stream=None, + call=None, + prompt=None, + notify=None, + markdown=None, + prompts=None, +): + with shelve.open("users") as db: + user_id = str(user_id) + if user_id not in db: + db[user_id] = {} + + settings = db[user_id] + + if model is not None: settings["model"] = model + if stream is not None: settings["stream"] = stream + if call is not None: settings["call"] = call + if prompt is not None: settings["prompt"] = prompt + if notify is not None: settings["notify"] = notify + if markdown is not None: settings["markdown"] = markdown + if prompts is not None: settings["prompts"] = prompts + + db[user_id] = settings + + +def delete_user_from_db(user_id): + with shelve.open("users") as db: + if str(user_id) in db: + del db[str(user_id)] + + +def reset_user_setting(user_id, key, value): + with shelve.open("users") as db: + user = db[str(user_id)] + user[key] = value + db[str(user_id)] = user + + +def ensure_user( + user_id, + model_name=DEFAULT_MODEL, + stream_mode=DEFAULT_STREAM, + call_mode=DEFAULT_CALL, + prompt_name=DEFAULT_PROMPT, + notify_mode=DEFAULT_NOTIFY, + markdown=DEFAULT_MARKDOWN, + prompts={}, +): + with shelve.open("users") as db: + key = str(user_id) + + if key not in db: + db[key] = { + "model": model_name, + "stream": stream_mode, + "call": call_mode, + "prompt": prompt_name, + "notify": notify_mode, + "markdown": markdown, + "prompts": prompts, + } + + +def get_user_config(user_id): + with shelve.open("users") as db: + config = db.get(str(user_id), {}) + defaults = { + "model": DEFAULT_MODEL, + "stream": DEFAULT_STREAM, + "call": DEFAULT_CALL, + "prompt": DEFAULT_PROMPT, + "notify": DEFAULT_NOTIFY, + "markdown": DEFAULT_MARKDOWN, + "prompts": {}, + } + updated = False + for key, value in defaults.items(): + if key not in config: + config[key] = value + updated = True + if updated: + db[str(user_id)] = config + return config + diff --git a/input_msg.py b/input_msg.py new file mode 100644 index 0000000..9bae20d --- /dev/null +++ b/input_msg.py @@ -0,0 +1,156 @@ +import string + +from random import choices + +from vars import * +from config import * +from helpers import get_user_config, set_user_setting + +from aiogram.types import ( + InlineKeyboardButton, + InlineKeyboardMarkup, + InlineQueryResultArticle, + InputTextMessageContent, + Message, +) + +async def da(bot, message, user_id): + config = get_user_config(user_id) + print(config) + if user_id in alo_command: + if message.chat.id == alo_command[user_id]["chat_id"]: + if alo_command[user_id]["action"] == "p_name": + alo_command[user_id]["action"] = "p_prompt" + alo_command[user_id]["name"] = message.text[:16] + return await bot.edit_message_text( + text=f"установи промпт для `{alo_command[user_id]['name']}`:", + chat_id=alo_command[user_id]["chat_id"], + message_id=alo_command[user_id]["message_id"], + reply_markup=InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=f"❌ отменить", callback_data=f"p_cancel%{user_id}" + ), + ], + ] + ) + ) + elif alo_command[user_id]["action"] == "p_prompt": + alo_command[user_id]["action"] = None + alo_command[user_id]["prompt"] = message.text + + if len(config["prompts"]) >= MAX_PROMPTS: + return await bot.edit_message_text( + text=f"невозможно создать новый промпт так как ты превысил лимит промптов da.", + chat_id=alo_command[user_id]["chat_id"], + message_id=alo_command[user_id]["message_id"], + reply_markup=InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=f"ок", callback_data=f"user_prompts%{user_id}" + ), + ], + ] + ) + ) + + while 1: + alo_command[user_id]["id"] = ''.join(choices(string.ascii_letters, k=10)) + if alo_command[user_id]["id"] not in config["prompts"]: + break + + config["prompts"] = config["prompts"] | { + alo_command[user_id]["id"]: { + "name": alo_command[user_id]["name"], + "text": alo_command[user_id]["prompt"], + "filer": False, + "public": False + } + } + + set_user_setting( + user_id, + prompts=config["prompts"] + ) + + return await bot.edit_message_text( + text=f"промпт `{alo_command[user_id]['name']}` создан!", + chat_id=alo_command[user_id]["chat_id"], + message_id=alo_command[user_id]["message_id"], + reply_markup=InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['id']}" + ), + ], + ] + ) + ) + elif alo_command[user_id]["action"] == "p_e_name": + alo_command[user_id]["action"] = None + alo_command[user_id]["name"] = message.text[:16] + + config["prompts"] = config["prompts"] | { + alo_command[user_id]["prompt_id"]: { + "name": alo_command[user_id]["name"], + "text": config["prompts"][alo_command[user_id]["prompt_id"]]["text"], + "filer": config["prompts"][alo_command[user_id]["prompt_id"]]["filer"], + "public": config["prompts"][alo_command[user_id]["prompt_id"]]["public"], + } + } + + set_user_setting( + user_id, + prompts = config["prompts"] + ) + + return await bot.edit_message_text( + text=f"имя промпта было изменено на `{alo_command[user_id]['name']}`.", + chat_id=alo_command[user_id]["chat_id"], + message_id=alo_command[user_id]["message_id"], + reply_markup=InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['prompt_id']}" + ), + ], + ] + ) + ) + elif alo_command[user_id]["action"] == "p_e_prompt": + alo_command[user_id]["action"] = None + alo_command[user_id]["prompt"] = message.text + + config["prompts"] = config["prompts"] | { + alo_command[user_id]["prompt_id"]: { + "name": config["prompts"][alo_command[user_id]["prompt_id"]]["name"], + "text": alo_command[user_id]["prompt"], + "filer": config["prompts"][alo_command[user_id]["prompt_id"]]["filer"], + "public": config["prompts"][alo_command[user_id]["prompt_id"]]["public"], + } + } + + set_user_setting( + user_id, + prompts=config["prompts"] + ) + + return await bot.edit_message_text( + text=f"текст промпта был изменён.", + chat_id=alo_command[user_id]["chat_id"], + message_id=alo_command[user_id]["message_id"], + reply_markup=InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['prompt_id']}" + ), + ], + ] + ) + ) + return None @@ -4,9 +4,9 @@ import base64 import io import sys import time -import string import gconfig +import input_msg # from aiogram.methods import SendMessageDraft from datetime import datetime @@ -36,6 +36,7 @@ from callbacks import * from statistics import * from colors import * from helpers import * +from vars import * from commands import * from dotenv import load_dotenv from random import uniform, shuffle, choices @@ -90,163 +91,9 @@ async def guest_middleware(handler, event, data): config = get_user_config(user_id) prompts = SYSTEM_PROMPTS | config["prompts"] p = prompts[config["prompt"]] - # внимание внизу самая умная система осторожнеее!!1!1 - if user_id in alo_command: - if message.chat.id == alo_command[user_id]["chat_id"]: - if alo_command[user_id]["action"] == "p_name": - alo_command[user_id]["action"] = "p_prompt" - alo_command[user_id]["name"] = message.text[:16] - return await bot.edit_message_text( - text=f"установи промпт для `{alo_command[user_id]['name']}`:", - chat_id=alo_command[user_id]["chat_id"], - message_id=alo_command[user_id]["message_id"], - reply_markup=InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=f"❌ отменить", callback_data=f"p_cancel%{user_id}" - ), - ], - ] - ) - ) - elif alo_command[user_id]["action"] == "p_prompt": - alo_command[user_id]["action"] = None - alo_command[user_id]["prompt"] = message.text - - if len(config["prompts"]) >= MAX_PROMPTS: - return await bot.edit_message_text( - text=f"невозможно создать новый промпт так как ты превысил лимит промптов da.", - chat_id=alo_command[user_id]["chat_id"], - message_id=alo_command[user_id]["message_id"], - reply_markup=InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=f"ок", callback_data=f"user_prompts%{user_id}" - ), - ], - ] - ) - ) - - while 1: - alo_command[user_id]["id"] = ''.join(choices(string.ascii_letters, k=10)) - if alo_command[user_id]["id"] not in config["prompts"]: - break - - config["prompts"] = config["prompts"] | { - alo_command[user_id]["id"]: { - "name": alo_command[user_id]["name"], - "text": alo_command[user_id]["prompt"], - "filer": False, - "public": False - } - } - - set_user_config( - user_id, - config.get("model"), - config.get("stream", True), - config.get("call"), - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config["prompts"] - ) - - return await bot.edit_message_text( - text=f"промпт `{alo_command[user_id]['name']}` создан!", - chat_id=alo_command[user_id]["chat_id"], - message_id=alo_command[user_id]["message_id"], - reply_markup=InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['id']}" - ), - ], - ] - ) - ) - elif alo_command[user_id]["action"] == "p_e_name": - alo_command[user_id]["action"] = None - alo_command[user_id]["name"] = message.text[:16] - - - config["prompts"] = config["prompts"] | { - alo_command[user_id]["prompt_id"]: { - "name": alo_command[user_id]["name"], - "text": config["prompts"][alo_command[user_id]["prompt_id"]]["text"], - "filer": config["prompts"][alo_command[user_id]["prompt_id"]]["filer"], - "public": config["prompts"][alo_command[user_id]["prompt_id"]]["public"], - } - } - - set_user_config( - user_id, - config.get("model"), - config.get("stream", True), - config.get("call"), - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config["prompts"] - ) - - return await bot.edit_message_text( - text=f"имя промпта было изменено на `{alo_command[user_id]['name']}`.", - chat_id=alo_command[user_id]["chat_id"], - message_id=alo_command[user_id]["message_id"], - reply_markup=InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['prompt_id']}" - ), - ], - ] - ) - ) - elif alo_command[user_id]["action"] == "p_e_prompt": - alo_command[user_id]["action"] = None - alo_command[user_id]["prompt"] = message.text - - - config["prompts"] = config["prompts"] | { - alo_command[user_id]["prompt_id"]: { - "name": config["prompts"][alo_command[user_id]["prompt_id"]]["name"], - "text": alo_command[user_id]["prompt"], - "filer": config["prompts"][alo_command[user_id]["prompt_id"]]["filer"], - "public": config["prompts"][alo_command[user_id]["prompt_id"]]["public"], - } - } - set_user_config( - user_id, - config.get("model"), - config.get("stream", True), - config.get("call"), - config.get("prompt"), - config.get("notify"), - config.get("markdown"), - config["prompts"] - ) - - return await bot.edit_message_text( - text=f"текст промпта был изменён.", - chat_id=alo_command[user_id]["chat_id"], - message_id=alo_command[user_id]["message_id"], - reply_markup=InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=f"✅ посмотреть", callback_data=f"vp%{user_id}%{alo_command[user_id]['prompt_id']}" - ), - ], - ] - ) - ) + if await input_msg.da(bot, message, user_id) != None: + return if p["filer"]: if event.guest_message: @@ -294,7 +141,7 @@ async def guest_middleware(handler, event, data): last_command_time[user_id][1] = True last_command_time[user_id][2] += [message.message_id] - await asyncio.sleep(uniform(0,0.5)) + await asyncio.sleep(uniform(0,0.2)) if event.message: try: @@ -314,11 +161,26 @@ async def guest_middleware(handler, event, data): voice = None + model = config["model"].split("*", 1) + if VOSK_API != "": if message.voice: voice = message.voice elif replied and replied.voice: voice = replied.voice + + process = { + "text": "wait", + "photo_a": "wait" if replied and replied.photo and MODELS[model[0]].get("vision", False) == False else None, + "photo": "wait" if message.photo and MODELS[model[0]][model[1]].get("vision", False) == False else None, + "stt": "wait" if voice else None, + } + + if event.message: + if (config["stream"] == "edit") or (config["stream"] == "native" and user_id == message.chat.id): + msg = await message.reply(make_graph(message, process)) + else: + gmsg = await g_answer(message, make_graph(message, process)) location = None if message.location: @@ -339,7 +201,7 @@ async def guest_middleware(handler, event, data): try: brat = await bot.download(voice, destination=buf) except Exception as e: - print(f"{YELLOW} -- voice err - {e}{RESET}") + print(f"{YELLOW} -- voice download err - {e}{RESET}") buf.seek(0) try: @@ -349,6 +211,12 @@ async def guest_middleware(handler, event, data): buf.read() ) except Exception as e: + process["stt"] = "error" + if event.message and msg: + await msg.edit_text(make_graph(message, process)) + elif event.guest_message and gmsg: + await bot.edit_message_text(text=make_graph(message, process), inline_message_id=gmsg.inline_message_id) + prompt = f"<голосовое сообщение>ошибка подключения к api stt</голосовое сообщение>{prompt}" print(f"{RED} -- voice err - {e}{RESET}") else: @@ -356,17 +224,15 @@ async def guest_middleware(handler, event, data): if message.document: - if message.document.file_size > 4096: - await mans(message, "слишком много данных не хочу отвечать☝️☝️") - return - file_bytes = io.BytesIO() - try: await bot.download(message.document, destination=file_bytes) file_bytes.seek(0) - file_content = file_bytes.read().decode("utf-8", errors="ignore") + if message.document.file_size > 9000: + file_content = file_bytes.read().decode("utf-8", errors="ignore")[:9000] + else: + file_content = file_bytes.read().decode("utf-8", errors="ignore") file_bytes.close() prompt = f"<файл>{file_content}</файл>{prompt}" @@ -376,20 +242,20 @@ async def guest_middleware(handler, event, data): return except Exception: - await mans(message, "файл не вошёл ало ошибка❌❌") + if msg: + await msg.edit_text(message, "файл не вошёл ало ошибка❌❌") return if replied and replied.document: - if replied.document.file_size > 4096: - await mans(message, "слишком много данных не хочу отвечать☝️☝️") - return - file_bytes = io.BytesIO() - try: await bot.download(replied.document, destination=file_bytes) file_bytes.seek(0) - file_content = file_bytes.read().decode("utf-8", errors="ignore") + if replied.document.file_size > 9000: + file_content = file_bytes.read().decode("utf-8", errors="ignore")[:9000] + else: + file_content = file_bytes.read().decode("utf-8", errors="ignore") + file_bytes.close() prompt = f"<файл>{file_content}</файл>{prompt}" except UnicodeDecodeError: await mans(message, "файл не вошёл❌") @@ -433,23 +299,30 @@ async def guest_middleware(handler, event, data): file_bytes = await bot.download(photo) image_bytes = file_bytes.read() b64_image = base64.b64encode(image_bytes).decode("utf-8") - images += [b64_image] + images += [{"data": b64_image, "process": "photo_a"}] except Exception as e: + process["photo_a"] = "error" + if event.message and msg: + await msg.edit_text(make_graph(message, process)) + elif event.guest_message and gmsg: + await bot.edit_message_text(text=make_graph(message, process), inline_message_id=gmsg.inline_message_id) + print(f"{RED} -- photo - {e}{RESET}") if message.photo and IMAGE_MODEL != "": try: - if event.message: - if not msg: - msg = await message.reply("👀") photo = message.photo[-1] file_bytes = await bot.download(photo) image_bytes = file_bytes.read() b64_image = base64.b64encode(image_bytes).decode("utf-8") - images += [b64_image] + images += [{"data": b64_image, "process": "photo"}] except Exception as e: - print(f"{RED} -- photo - {e}{RESET}") - + process["photo"] = "error" + if event.message and msg: + await msg.edit_text(make_graph(message, process)) + elif event.guest_message and gmsg: + await bot.edit_message_text(text=make_graph(message, process), inline_message_id=gmsg.inline_message_id) + print(f"{RED} -- photo - {e}{RESET}") prompt = f"{prompt}\n{user_text}" if replied_text: prompt = f"<ответ на>{replied_text}</ответ> {prompt}" @@ -475,7 +348,10 @@ async def guest_middleware(handler, event, data): ] ) if event.guest_message: - await g_answer(message, alloh_one_text, reply_markup=reply_markup_url) + if gmsg: + await bot.edit_message_text(text=alloh_one_text, inline_message_id=gmsg.inline_message_id, reply_markup=reply_markup_url) + else: + await g_answer(message, alloh_one_text, reply_markup=reply_markup_url) elif event.message: await message.reply_rich(InputRichMessage(markdown="# новый крутой стилёк\n*da*\n```\nтестовое сообщение врат\n```")) await message.answer(alloh_text, reply_markup=reply_markup) @@ -489,10 +365,12 @@ async def guest_middleware(handler, event, data): if stream == "edit": if event.message: + im_model = IMAGE_MODEL.split("*", 1) + tx_model = config["model"].split("*", 1) if msg: message_id = msg.message_id else: - msg = await message.reply("💬") + msg = await message.reply("💭") message_id = msg.message_id elif event.guest_message: stream = "none" @@ -517,6 +395,9 @@ async def guest_middleware(handler, event, data): user_id=user_id, message_id=message_id, images=images, + msg=msg, + process=process, + message=message ) else: result = await generate( @@ -526,6 +407,7 @@ async def guest_middleware(handler, event, data): user_id=user_id, message_id=None, images=images, + inline_id=gmsg.inline_message_id ) result = parse_tools(result) @@ -633,8 +515,23 @@ async def guest_middleware(handler, event, data): try: if event.guest_message: - await g_answer(message, result, user_id=user_id) + if len(result) > 4000: + result = result[:4000] + "...\n\n__сообщение твой большой и он сокращен__" + if gmsg: + await bot.edit_message_text(text=result, inline_message_id=gmsg.inline_message_id) + else: + await g_answer(message, result, user_id=user_id) elif event.message: + if len(result) > 4000: + if msg: + await msg.delete() + file = BufferedInputFile( + file=result.encode("utf-8"), + filename=result.replace("\n", "").replace(" ", "_")[:5] + ".txt" + ) + return await message.reply_document( + document=file + ) if msg: if stream == "native": await msg.delete() @@ -653,7 +550,12 @@ async def guest_middleware(handler, event, data): kwargs["parse_mode"] = None try: if event.guest_message: - await g_answer(message, result) + if len(result) > 4000: + result = result[:4000] + "...\n\n__сообщение твой большой и он сокращен__" + if gmsg: + await bot.edit_message_text(text=result, inline_message_id=gmsg.inline_message_id, parse_mode="None") + else: + await g_answer(message, result, parse_mode="None") elif event.message: if msg: if stream == "native": @@ -777,6 +679,7 @@ async def chosen_inline_result_handler(chosen_result: ChosenInlineResult): await bot.edit_message_text( text=error["message"], inline_message_id=inline_message_id, + parse_mode=None ) print(f"{RED} -- {error['type']} -- {error['message']}") return @@ -823,3 +726,4 @@ async def main(): if __name__ == "__main__": asyncio.run(main()) + diff --git a/requirements.txt b/requirements.txt index e652d79..2b3414d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,3 @@ aiogram==3.29.1 python-dotenv==1.2.1 pillow==12.0.0 requests -openai diff --git a/supergenerator.py b/supergenerator.py index 1377247..4df694b 100644 --- a/supergenerator.py +++ b/supergenerator.py @@ -2,233 +2,24 @@ import random import re import shelve import time +import ai +import json + from configparser import DEFAULTSECT from pprint import pprint -from openai import AsyncOpenAI - from statistics import * from colors import * +from helpers import * from config import * +from vars import * -last_command_time = {} -last_error_time = {} -last_block_time = {} -alo_command = {} -user_contexts = {} - - -def get_clients(): - provs = {} - for provider, settings in PROVIDERS.items(): - if settings.get("module") == "openai": - provs[provider] = AsyncOpenAI( - base_url=settings.get("url"), api_key=settings.get("key") - ) - return provs - - -providers = get_clients() - - -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 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": "лимит токенов закончился у провайдера врат. подожди или смени модель.", - } - 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"<think>.*?</think>", "", text, flags=re.DOTALL) - result = re.sub(r"<thought>.*?</thought>", "", text, flags=re.DOTALL) - return result - - -def get_all_users(only_notify=False): - with shelve.open("users") as db: - return {k: db[k] for k in db.keys() if not only_notify or db[k].get("notify") == "da"} - - -def get_all_user_ids(only_notify=False): - ids = [] - with shelve.open("users") as db: - for user_id in db.keys(): - if only_notify and db[user_id].get("notify") != "da": - continue - try: - ids.append(int(user_id)) - except ValueError: - pass - return ids - - -def set_user_config( - user_id, - model_name, - stream_mode=DEFAULT_STREAM, - call_mode=DEFAULT_CALL, - prompt_name=DEFAULT_PROMPT, - notify_mode=DEFAULT_NOTIFY, - markdown=DEFAULT_MARKDOWN, - prompts={}, -): - with shelve.open("users") as db: - db[str(user_id)] = { - "model": model_name, - "stream": stream_mode, - "call": call_mode, - "prompt": prompt_name, - "notify": notify_mode, - "markdown": markdown, - "prompts": prompts, - } - - -def delete_user_from_db(user_id): - with shelve.open("users") as db: - if str(user_id) in db: - del db[str(user_id)] - - -def reset_user_setting(user_id, key, value): - with shelve.open("users") as db: - user = db[str(user_id)] - user[key] = value - db[str(user_id)] = user - - -def ensure_user( - user_id, - model_name=DEFAULT_MODEL, - stream_mode=DEFAULT_STREAM, - call_mode=DEFAULT_CALL, - prompt_name=DEFAULT_PROMPT, - notify_mode=DEFAULT_NOTIFY, - markdown=DEFAULT_MARKDOWN, - prompts={}, -): - with shelve.open("users") as db: - key = str(user_id) - - if key not in db: - db[key] = { - "model": model_name, - "stream": stream_mode, - "call": call_mode, - "prompt": prompt_name, - "notify": notify_mode, - "markdown": markdown, - "prompts": prompts, - } - - -def get_user_config(user_id): - with shelve.open("users") as db: - config = db.get(str(user_id), {}) - defaults = { - "model": DEFAULT_MODEL, - "stream": DEFAULT_STREAM, - "call": DEFAULT_CALL, - "prompt": DEFAULT_PROMPT, - "notify": DEFAULT_NOTIFY, - "markdown": DEFAULT_MARKDOWN, - "prompts": {}, - } - updated = False - for key, value in defaults.items(): - if key not in config: - config[key] = value - updated = True - if updated: - db[str(user_id)] = config - return config - +from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError async def generate( - prompt: str, bot=None, user_id=None, chat_id=None, message_id=None, images=None + prompt: str, bot=None, user_id=None, chat_id=None, message_id=None, images=None, msg=None, process=None, message=None, inline_id=None ) -> str: if user_id: if user_id not in user_contexts: @@ -265,9 +56,11 @@ async def generate( f"2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит" return text - if stream_cf == "native" and user_id == chat_id and settings.get("nostream") == False: + if stream_cf == "native" and user_id == chat_id and settings.get("nostream", False) == False: + stream = True + elif stream_cf == "edit" and chat_id and message_id and settings.get("nostream", False) == False: stream = True - elif stream_cf == "edit" and chat_id and message_id and settings.get("nostream") == False: + elif stream_cf == "edit" or stream_cf == "native" and inline_id: stream = True else: stream = False @@ -281,10 +74,20 @@ async def generate( else: for image in images: try: - image_text = await image2text(image) + if process and msg and message: + process[image["process"]] = "make" + await msg.edit_text(make_graph(message, process)) + image_text = await image2text(image["data"]) prompt = f"<фото>{image_text}</фото>\n{prompt}" except Exception as e: + if process and msg and message: + process[image["process"]] = "error" + await msg.edit_text(make_graph(message, process)) print(f"{RED} -- err photo - {e} : {config.get('model', '')}{RESET}") + else: + if process and msg and message: + process[image["process"]] = "done" + await msg.edit_text(make_graph(message, process)) content += [{"type": "text", "text": prompt}] @@ -322,15 +125,19 @@ async def generate( add_one_to("stats/gens") try: - client = providers[model[0]] + provider = PROVIDERS[model[0]] except Exception: text = "❌произошла ошибка, возможные проблемы:\n" \ "1. у вас выбрана удалённая модель или провайдер\n" \ "2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит" return text - + + if process and msg and message: + process["text"] = "make" + await msg.edit_text(make_graph(message, process)) + text = await openai_generate_text( - oai=client, + api=provider, bot=bot, model=model[1], settings=settings, @@ -340,6 +147,7 @@ async def generate( chat_id=chat_id, draft_id=chat_id, message_id=message_id, + inline_id=inline_id ) if user_id: @@ -352,8 +160,8 @@ async def generate( async def image2text(image) -> str: if IMAGE_MODEL == "": return "" - model = IMAGE_MODEL.split("*", 2) - client = providers[model[0]] + model = IMAGE_MODEL.split("*", 1) + api = PROVIDERS[model[0]] text = "" messages = [ { @@ -364,24 +172,26 @@ async def image2text(image) -> str: ], } ] - response = await client.responses.create( - model=model[1], input=messages, stream=False - ) + async for response in ai.responses( + url=api["url"], api_key=api["key"], model=model[1], input=messages, stream=False + ): + pass text = response.output_text return text async def openai_generate_text( - oai: AsyncOpenAI, + api, bot, model, settings, messages, stream, stream_cf, - chat_id, - draft_id, - message_id, + chat_id=None, + draft_id=None, + message_id=None, + inline_id=None ) -> str: try: extra_body = { @@ -389,56 +199,99 @@ async def openai_generate_text( } if settings.get("noexb"): extra_body = None - - completion = await oai.chat.completions.create( - model=model, - messages=messages, - stream=stream, - max_tokens=MAX_TOKENS, - extra_body=extra_body - ) + + alo = { + "url": api["url"], + "api_key": api["key"], + "model": model, + "messages": messages, + "stream": stream, + "max_tokens": MAX_TOKENS, + "extra": extra_body + } + if stream: message = "" + t_counter = 0 counter = 0 + counter_2 = 1 if not draft_id: draft_id = chat_id - async for event in completion: - content = event.choices[0].delta.content + async for chunk in ai.completions(**alo): + # chunk = json.loads(chunk) + try: + content = chunk["choices"][0]["delta"]["content"] + except: + continue if content: message += content - counter += 1 - if stream_cf == "native": - counter_limit = settings.get("n_tok") - else: - counter_limit = settings.get("e_tok") + counter += len(content) + t_counter += 1 - if counter % counter_limit == 0: + if counter > MAX_SYMBOLS: + break + + if int(counter / STREAMING_SPLIT_SYMBOLS) == counter_2: + counter_2 += 1 display_text, s = clean_tail_repeats(message) if s > 0: display_text += f"*... <{s} обрезано>*" if display_text.count("```") % 2 != 0: display_text += "\n```" - try: - if stream_cf == "native": - await bot.send_message_draft( - chat_id=chat_id, - draft_id=draft_id, - text=display_text, - parse_mode="Markdown", - ) - elif stream_cf == "edit": - await bot.edit_message_text( - chat_id=chat_id, - message_id=message_id, - text=display_text, - parse_mode="Markdown", - ) - except Exception as e: - print(f"{YELLOW} -- {e}{RESET}") + + if counter < 3950: + display_text += "▋" + + try: + if stream_cf == "native" and chat_id and draft_id: + await bot.send_message_draft( + chat_id=chat_id, + draft_id=draft_id, + text=display_text, + ) + elif stream_cf == "edit" and chat_id and message_id: + await bot.edit_message_text( + chat_id=chat_id, + message_id=message_id, + text=display_text, + ) + elif stream_cf == "edit" or stream_cf == "native" and inline_id: + await bot.edit_message_text( + inline_message_id=inline_id, + text=display_text, + ) + except TelegramBadRequest as e: + if "can't parse entities" in str(e): + if stream_cf == "native" and chat_id and draft_id: + await bot.send_message_draft( + chat_id=chat_id, + draft_id=draft_id, + text=display_text, + parse_mode=None, + ) + elif stream_cf == "edit" and chat_id and message_id: + await bot.edit_message_text( + chat_id=chat_id, + message_id=message_id, + text=display_text, + parse_mode=None, + ) + elif stream_cf == "edit" or stream_cf == "native" and inline_id: + await bot.edit_message_text( + inline_message_id=inline_id, + text=display_text, + parse_mode=None, + ) + else: + print(f"{YELLOW} -- {e}{RESET}") + except Exception as e: + print(f"{YELLOW} -- {e}{RESET}") text = message else: - text = completion.choices[0].message.content + async for completion in ai.completions(**alo): + pass + text = completion["choices"][0]["message"]["content"] except Exception as e: error = parse_response(str(e).lower()) print(f"{RED} -- {error['type']} - {e}{RESET}") @@ -0,0 +1,5 @@ +last_command_time = {} +last_error_time = {} +last_block_time = {} +alo_command = {} +user_contexts = {} |