телифон связь поиск в интернате

This commit is contained in:
huker667 committed 2026-09-16 16:52:32 +03:00
1 parent d78c1b55c0
commit 374c01458d
6 files changed
+206 -23

No files matched your search

+16
View File
@@ -52,6 +52,7 @@ commands = [
"/reset", "/reset",
"/tben", "/tben",
"/group", "/group",
"/cost",
] ]
@router.message(Command("stats")) @router.message(Command("stats"))
@@ -560,6 +561,21 @@ async def clear_handler(message: Message):
print(f"{RED} -- {e}{RESET}") print(f"{RED} -- {e}{RESET}")
@router.message(Command("cost"))
async def cost_handler(message: Message):
if message.sender_chat:
user_id = message.sender_chat.id
else:
user_id = message.from_user.id
t = get_tokens(user_id)
await message.reply(
f"💸 *твои токены:*\n"
f"вход: `{t['input']}`\n"
f"выход: `{t['output']}`\n"
f"запросов: `{t['requests']}`"
)
@router.message(Command("markpidor")) @router.message(Command("markpidor"))
async def alo(message: Message): async def alo(message: Message):
await message.reply_rich(InputRichMessage(markdown="# ало")) await message.reply_rich(InputRichMessage(markdown="# ало"))
+83
View File
@@ -2,6 +2,7 @@ import re
import time import time
import shelve import shelve
import requests import requests
from datetime import datetime
from aiogram.methods import AnswerGuestQuery, SendPoll from aiogram.methods import AnswerGuestQuery, SendPoll
from aiogram.types import InlineQueryResultArticle, InputTextMessageContent, InputRichMessageContent, InputRichMessage, Message from aiogram.types import InlineQueryResultArticle, InputTextMessageContent, InputRichMessageContent, InputRichMessage, Message
@@ -571,3 +572,85 @@ def set_group_setting(
db[group_id] = settings db[group_id] = settings
def apply_time_tags(text):
now = datetime.now()
text = text.replace("{{date}}", now.strftime("%d.%m.%Y"))
text = text.replace("{{time}}", now.strftime("%H:%M"))
text = text.replace("{{now}}", now.strftime("%d.%m.%Y %H:%M"))
return text
def web_search(query):
r = requests.get(
"https://lite.duckduckgo.com/lite/",
params={"q": query},
headers={"User-Agent": "Mozilla/5.0"},
timeout=10
)
r.raise_for_status()
links = re.findall(r"<a[^>]*class=['\"]result-link['\"][^>]*>(.*?)</a>", r.text, re.DOTALL)
snippets = re.findall(r"<td[^>]*class=['\"]result-snippet['\"][^>]*>(.*?)</td>", r.text, re.DOTALL)
results = []
for i in range(min(5, len(links))):
title = re.sub(r"<[^>]+>", "", links[i]).strip()
snippet = re.sub(r"<[^>]+>", "", snippets[i]).strip()[:300] if i < len(snippets) else ""
results.append(f"{title}\n{snippet}")
if not results:
return "ничего не нашлось"
return "\n\n".join(results)
def wiki_search(query):
r = requests.get(
"https://ru.wikipedia.org/w/rest.php/v1/search/page",
params={"q": query, "limit": 3},
headers={"User-Agent": "uzbekgpt/1.0"},
timeout=10
)
r.raise_for_status()
results = []
for p in r.json().get("pages", []):
title = p.get("title", "")
excerpt = re.sub(r"<[^>]+>", "", p.get("excerpt", ""))
results.append(f"{title}\n{excerpt[:400]}")
if not results:
return "ничего не нашлось в википедии"
return "\n\n".join(results)
def extract_tool(text):
m = re.search(r"<search>(.*?)</search>", text, re.DOTALL)
if m:
return "search", m.group(1).strip()
m = re.search(r"<wiki>(.*?)</wiki>", text, re.DOTALL)
if m:
return "wiki", m.group(1).strip()
return None
def add_tokens(user_id, input_t, output_t):
with shelve.open("tokens") as db:
key = str(user_id)
data = db.get(key, {"input": 0, "output": 0, "requests": 0})
data["input"] += input_t
data["output"] += output_t
data["requests"] += 1
db[key] = data
def get_tokens(user_id):
with shelve.open("tokens") as db:
return db.get(str(user_id), {"input": 0, "output": 0, "requests": 0})
async def alert_admin(bot, provider_name, error_text):
current = time.time()
if provider_name in provider_alert_time and current - provider_alert_time[provider_name] < 600:
return
provider_alert_time[provider_name] = current
try:
await bot.send_message(ADMIN_ID, f"🚨 провайдер `{provider_name}` кажется упал:\n{str(error_text)[:300]}")
except Exception as e:
print(f" -- alert admin - {e}")
+11
View File
@@ -72,3 +72,14 @@ OLD_MD = """
NEW_MD = """ NEW_MD = """
иногда используй Markdown для разметки (можно почти весь, даже заголовки можно) иногда используй Markdown для разметки (можно почти весь, даже заголовки можно)
""" """
TOOLS_PROMPT = """
инструменты:
если не знаешь ответ или нужны свежие данные из интернета используй поиск:
ответь сообщением только с тегом и запросом внутри, без другого текста:
<search>запрос</search>
или для статьи из википедии:
<wiki>запрос</wiki>
после получения результатов ответишь нормально пользователю.
не используй поиск если знаешь ответ или вопрос простой.
"""
+94 -23
View File
@@ -1,4 +1,3 @@
import json
import ai import ai
from statistics import * from statistics import *
@@ -6,6 +5,7 @@ from colors import *
from helpers import * from helpers import *
from config import * from config import *
from vars import * from vars import *
from prompts import TOOLS_PROMPT
from aiogram.exceptions import TelegramBadRequest from aiogram.exceptions import TelegramBadRequest
@@ -13,6 +13,8 @@ from aiogram.exceptions import TelegramBadRequest
async def generate( async def generate(
prompt: str, bot=None, user_id=None, chat_id=None, message_id=None, images=None, msg=None, process=None, message=None, inline_id=None, system_prompt=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, system_prompt=None
) -> str: ) -> str:
prompt = apply_time_tags(prompt)
if user_id: if user_id:
if user_id not in user_contexts: if user_id not in user_contexts:
user_contexts[user_id] = [] user_contexts[user_id] = []
@@ -48,6 +50,8 @@ async def generate(
f"2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит" f"2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит"
return text return text
system_prompt += TOOLS_PROMPT
content = [] content = []
if images and not is_auto: if images and not is_auto:
@@ -98,11 +102,15 @@ async def generate(
sp = system_prompt sp = system_prompt
else: else:
sp = SYSTEM_PROMPTS[DEFAULT_PROMPT]["text"]+ADD_TO_PROMPT+OLD_MD sp = SYSTEM_PROMPTS[DEFAULT_PROMPT]["text"]+ADD_TO_PROMPT+OLD_MD
sp += TOOLS_PROMPT
messages = [{"role": "system", "content": sp}] + [ messages = [{"role": "system", "content": sp}] + [
{"role": "user", "content": content} {"role": "user", "content": content}
] ]
text = "" text = ""
total_in = 0
total_out = 0
tools_used = []
if str(user_id) in temp_benned: if str(user_id) in temp_benned:
return temp_benned[str(user_id)] return temp_benned[str(user_id)]
@@ -149,6 +157,7 @@ async def generate(
auto_content += [{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image['data']}"}}] auto_content += [{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image['data']}"}}]
auto_messages = [{"role": "system", "content": messages[0]["content"]}, {"role": "user", "content": auto_content}] + messages[2:] auto_messages = [{"role": "system", "content": messages[0]["content"]}, {"role": "user", "content": auto_content}] + messages[2:]
sent_messages = auto_messages
text = await openai_generate_text( text = await openai_generate_text(
api=provider, api=provider,
@@ -164,6 +173,10 @@ async def generate(
message_id=message_id, message_id=message_id,
inline_id=inline_id inline_id=inline_id
) )
total_in += text.get("input") or 0
total_out += text.get("output") or 0
if text["type"] == "error" and text.get("etype") in ["connection", "timeout", "int", "incomplete"]:
await alert_admin(bot, provider_name, text["text"])
last_type = text["type"] last_type = text["type"]
if text == "": if text == "":
text = {"type": "error", "text": "все модели в автовыборе вернули ошибку"} text = {"type": "error", "text": "все модели в автовыборе вернули ошибку"}
@@ -177,6 +190,7 @@ async def generate(
"2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит" "2. конфиг бота настроен неправильно и надо связаться с тем кто его хостит"
settings = MODELS.get(provider_name, {}).get(model_name, {}) settings = MODELS.get(provider_name, {}).get(model_name, {})
key = get_key(provider_name, model_str) key = get_key(provider_name, model_str)
sent_messages = messages
if stream_cf == "native" and user_id == chat_id and settings.get("nostream", False) == False: if stream_cf == "native" and user_id == chat_id and settings.get("nostream", False) == False:
stream = True stream = True
@@ -205,8 +219,61 @@ async def generate(
message_id=message_id, message_id=message_id,
inline_id=inline_id inline_id=inline_id
) )
total_in += text.get("input") or 0
total_out += text.get("output") or 0
if text["type"] == "error" and text.get("etype") in ["connection", "timeout", "int", "incomplete"]:
await alert_admin(bot, provider_name, text["text"])
for _ in range(2):
if text.get("type") != "da":
break
tool = extract_tool(text.get("text", ""))
if not tool:
break
kind, query = tool
try:
if kind == "search":
tool_result = web_search(query)
else:
tool_result = wiki_search(query)
tools_used.append(kind)
except Exception as e:
print(f"{RED} -- tool {kind} - {e}{RESET}")
tool_result = f"поиск не сработал ({e})"
tool_exchange = [
{"role": "assistant", "content": [{"type": "text", "text": text["text"]}]},
{"role": "user", "content": [{"type": "text", "text": f"<результаты поиска>\n{tool_result[:3000]}\n</результаты>\nответь на вопрос используя эти данные. тег поиска больше не пиши."}]},
]
sent_messages += tool_exchange
if user_id:
user_contexts[user_id] = (user_contexts[user_id] + tool_exchange)[-MAX_CONTEXT:]
text = await openai_generate_text(
api=provider,
api_key=key,
bot=bot,
model=model_name,
settings=settings,
messages=sent_messages,
stream=False,
stream_cf=stream_cf,
chat_id=chat_id,
draft_id=chat_id,
message_id=message_id,
inline_id=inline_id
)
total_in += text.get("input") or 0
total_out += text.get("output") or 0
if tools_used and text.get("type") == "da":
tool_names = []
if "search" in tools_used:
tool_names.append("поиск (duckduckgo)")
if "wiki" in tools_used:
tool_names.append("википедия")
text["text"] = "🔍 использован: " + ", ".join(tool_names) + "\n\n" + text["text"]
if user_id: if user_id:
add_tokens(user_id, total_in, total_out)
user_contexts[user_id].append({"role": "assistant", "content": [{"type": "text", "text": text["text"]}]}) user_contexts[user_id].append({"role": "assistant", "content": [{"type": "text", "text": text["text"]}]})
user_contexts[user_id] = user_contexts[user_id][-MAX_CONTEXT:] user_contexts[user_id] = user_contexts[user_id][-MAX_CONTEXT:]
@@ -259,6 +326,8 @@ async def openai_generate_text(
inline_id=None, inline_id=None,
api_key=None api_key=None
) -> str: ) -> str:
usage_in = 0
usage_out = 0
try: try:
extra_body = { extra_body = {
"think": "false" "think": "false"
@@ -288,13 +357,19 @@ async def openai_generate_text(
try: try:
content = chunk["choices"][0]["delta"]["content"] content = chunk["choices"][0]["delta"]["content"]
except: except:
if isinstance(chunk, dict) and chunk.get("usage"):
u = chunk["usage"]
usage_in = u.get("prompt_tokens", 0) or 0
usage_out = u.get("completion_tokens", 0) or 0
continue
err_text = extract_error(chunk) err_text = extract_error(chunk)
if err_text: if err_text:
error = parse_response(err_text.lower()) error = parse_response(err_text.lower())
print(f"{RED} -- {error['type']} - {err_text}{RESET}") print(f"{RED} -- {error['type']} - {err_text}{RESET}")
return { return {
"type": "error", "type": "error",
"text": error["message"] "text": error["message"],
"etype": error["type"]
} }
if isinstance(chunk, dict) and "choices" not in chunk: if isinstance(chunk, dict) and "choices" not in chunk:
stream_error = str(chunk)[:300] stream_error = str(chunk)[:300]
@@ -371,7 +446,8 @@ async def openai_generate_text(
print(f"{RED} -- {error['type']} - {stream_error}{RESET}") print(f"{RED} -- {error['type']} - {stream_error}{RESET}")
return { return {
"type": "error", "type": "error",
"text": error["message"] "text": error["message"],
"etype": error["type"]
} }
else: else:
async for completion in ai.completions(**alo): async for completion in ai.completions(**alo):
@@ -385,35 +461,27 @@ async def openai_generate_text(
print(f"{RED} -- {error['type']} - {err_text}{RESET}") print(f"{RED} -- {error['type']} - {err_text}{RESET}")
return { return {
"type": "error", "type": "error",
"text": error["message"] "text": error["message"],
"etype": error["type"]
} }
error = parse_response(str(completion).lower()) error = parse_response(str(completion).lower())
print(f"{RED} -- {error['type']} - {completion}{RESET}") print(f"{RED} -- {error['type']} - {completion}{RESET}")
return { return {
"type": "error", "type": "error",
"text": error["message"] "text": error["message"],
"etype": error["type"]
} }
if isinstance(completion, dict) and completion.get("usage"):
u = completion["usage"]
usage_in = u.get("prompt_tokens", 0) or 0
usage_out = u.get("completion_tokens", 0) or 0
except Exception as e: except Exception as e:
error = parse_response(str(e).lower()) error = parse_response(str(e).lower())
print(f"{RED} -- {error['type']} - {e}{RESET}") print(f"{RED} -- {error['type']} - {e}{RESET}")
err_str = str(e)
try:
status_code = int(err_str.split(" ", 1)[0])
except ValueError:
status_code = 0
if 400 <= status_code < 500:
debug_alo = {k: v for k, v in alo.items() if k != "api_key"}
return {
"type": "error",
"text": error["message"] + "\n\n" \
f"модель: `{model}`\n" \
f"статус: `{status_code}`\n" \
f"raw: `{err_str[:500]}`\n" \
f"запрос:\n```{json.dumps(debug_alo, ensure_ascii=False)[:1200]}\n```"
}
return { return {
"type": "error", "type": "error",
"text": error["message"] "text": error["message"],
"etype": error["type"]
} }
else: else:
text, s = clean_tail_repeats(text) text, s = clean_tail_repeats(text)
@@ -422,9 +490,12 @@ async def openai_generate_text(
if text == "": if text == "":
return { return {
"type": "error", "type": "error",
"text": "модель вернула пустой ответ" "text": "модель вернула пустой ответ",
"etype": "empty"
} }
return { return {
"type": "da", "type": "da",
"text": text "text": text,
"input": usage_in,
"output": usage_out
} }
BIN
View File
Binary file not shown.
+2
View File
@@ -12,3 +12,5 @@ user_contexts = {}
temp_benned = {} temp_benned = {}
# последние сообщения групп для подглядывания # последние сообщения групп для подглядывания
group_last_messages = {} group_last_messages = {}
# чтобы не спамить админу алертами при падении провайдера
provider_alert_time = {}