Добавлена возможность пересылки другого сообщения при обращении к боту.
This commit is contained in:
parent
3db3f13cda
commit
2296176b1c
3 changed files with 60 additions and 24 deletions
17
ai_agent.py
17
ai_agent.py
|
|
@ -31,14 +31,27 @@ class ChatContext:
|
||||||
self.messages.pop()
|
self.messages.pop()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass()
|
||||||
|
class AiMessage:
|
||||||
|
user_name: str = None
|
||||||
|
text: str = None
|
||||||
|
|
||||||
|
|
||||||
class AiAgent:
|
class AiAgent:
|
||||||
def __init__(self, api_token: str):
|
def __init__(self, api_token: str):
|
||||||
self.client = OpenRouter(api_key=api_token)
|
self.client = OpenRouter(api_key=api_token)
|
||||||
self.chat_contexts: Dict[int, ChatContext] = {}
|
self.chat_contexts: Dict[int, ChatContext] = {}
|
||||||
|
|
||||||
async def get_reply(self, chat_id: int, chat_prompt: str, user_name: str, message: str) -> str:
|
async def get_reply(self, chat_id: int, chat_prompt: str,
|
||||||
|
message: AiMessage, forwarded_message: Optional[AiMessage]) -> str:
|
||||||
|
message_text = message.text
|
||||||
|
if forwarded_message:
|
||||||
|
message_text += '\n<Цитируемое сообщение от {}>\n'.format(forwarded_message.user_name)
|
||||||
|
message_text += forwarded_message.text + '\n'
|
||||||
|
message_text += '<Конец цитаты>'
|
||||||
|
|
||||||
context = self._get_chat_context(chat_id, chat_prompt)
|
context = self._get_chat_context(chat_id, chat_prompt)
|
||||||
context.add_message(role="user", content=f"[{user_name}]: {message}")
|
context.add_message(role="user", content=f"[{message.user_name}]: {message_text}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get response from OpenRouter
|
# Get response from OpenRouter
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from aiogram.types.user import User
|
||||||
from aiogram.enums.content_type import ContentType
|
from aiogram.enums.content_type import ContentType
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
from ai_agent import AiAgent
|
from ai_agent import AiAgent, AiMessage
|
||||||
import tg.tg_database as database
|
import tg.tg_database as database
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
@ -34,6 +34,17 @@ ACCEPTED_CONTENT_TYPES: list[ContentType] = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def get_user_name_for_ai(user: User):
|
||||||
|
if user.first_name and user.last_name:
|
||||||
|
return "{} {}".format(user.first_name, user.last_name)
|
||||||
|
elif user.first_name:
|
||||||
|
return user.first_name
|
||||||
|
elif user.username:
|
||||||
|
return user.username
|
||||||
|
else:
|
||||||
|
return str(user.id)
|
||||||
|
|
||||||
|
|
||||||
@router.message(F.content_type.in_(ACCEPTED_CONTENT_TYPES))
|
@router.message(F.content_type.in_(ACCEPTED_CONTENT_TYPES))
|
||||||
async def any_message_handler(message: Message):
|
async def any_message_handler(message: Message):
|
||||||
chat_id = message.chat.id
|
chat_id = message.chat.id
|
||||||
|
|
@ -54,26 +65,26 @@ async def any_message_handler(message: Message):
|
||||||
if bot_user is None:
|
if bot_user is None:
|
||||||
bot_user = await message.bot.get_me()
|
bot_user = await message.bot.get_me()
|
||||||
|
|
||||||
|
ai_message = AiMessage()
|
||||||
|
ai_fwd_message: Optional[AiMessage] = None
|
||||||
|
|
||||||
# Ответ на сообщение бота
|
# Ответ на сообщение бота
|
||||||
if message.reply_to_message and message.reply_to_message.from_user.id == bot_user.id:
|
if message.reply_to_message and message.reply_to_message.from_user.id == bot_user.id:
|
||||||
message_text = message.text
|
ai_message.text = message.text
|
||||||
else:
|
else:
|
||||||
# Сообщение содержит @bot_username
|
# Сообщение содержит @bot_username
|
||||||
bot_username_mention = '@' + bot_user.username
|
bot_username_mention = '@' + bot_user.username
|
||||||
if message.content_type == ContentType.TEXT and message.text.find(bot_username_mention) != -1:
|
if message.content_type == ContentType.TEXT and message.text.find(bot_username_mention) != -1:
|
||||||
message_text = message.text.replace(bot_username_mention, bot_user.first_name)
|
ai_message.text = message.text.replace(bot_username_mention, bot_user.first_name)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
if message.from_user.first_name and message.from_user.last_name:
|
if message.reply_to_message and message.reply_to_message.content_type == ContentType.TEXT:
|
||||||
user_name = "{} {}".format(message.from_user.first_name, message.from_user.last_name)
|
ai_fwd_message = (
|
||||||
elif message.from_user.first_name:
|
AiMessage(user_name=await get_user_name_for_ai(message.reply_to_message.from_user),
|
||||||
user_name = message.from_user.first_name
|
text=message.reply_to_message.text))
|
||||||
elif message.from_user.username:
|
|
||||||
user_name = message.from_user.username
|
|
||||||
else:
|
|
||||||
user_name = str(message.from_user.id)
|
|
||||||
|
|
||||||
|
ai_message.user_name = await get_user_name_for_ai(message.from_user)
|
||||||
chat_prompt = chat['ai_prompt']
|
chat_prompt = chat['ai_prompt']
|
||||||
|
|
||||||
global agent
|
global agent
|
||||||
|
|
@ -82,7 +93,7 @@ async def any_message_handler(message: Message):
|
||||||
agent = AiAgent(message.bot.config['openrouter_token'])
|
agent = AiAgent(message.bot.config['openrouter_token'])
|
||||||
|
|
||||||
await message.bot.send_chat_action(chat_id, 'typing')
|
await message.bot.send_chat_action(chat_id, 'typing')
|
||||||
await message.reply(await agent.get_reply(chat_id, chat_prompt, user_name, message_text))
|
await message.reply(await agent.get_reply(chat_id, chat_prompt, ai_message, ai_fwd_message))
|
||||||
|
|
||||||
|
|
||||||
def clear_ai_chat_context(chat_id: int):
|
def clear_ai_chat_context(chat_id: int):
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from vkbottle import API
|
||||||
from vkbottle.bot import Message
|
from vkbottle.bot import Message
|
||||||
from vkbottle.framework.labeler import BotLabeler
|
from vkbottle.framework.labeler import BotLabeler
|
||||||
from vkbottle_types.codegen.objects import GroupsGroup
|
from vkbottle_types.codegen.objects import GroupsGroup
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
from ai_agent import AiAgent
|
from ai_agent import AiAgent, AiMessage
|
||||||
import vk.vk_database as database
|
import vk.vk_database as database
|
||||||
|
|
||||||
labeler = BotLabeler()
|
labeler = BotLabeler()
|
||||||
|
|
@ -15,6 +16,14 @@ agent: Optional[AiAgent] = None
|
||||||
bot_user: Optional[GroupsGroup] = None
|
bot_user: Optional[GroupsGroup] = None
|
||||||
|
|
||||||
|
|
||||||
|
async def get_user_name_for_ai(api: API, user_id: int):
|
||||||
|
user = await api.users.get(user_ids=[user_id])
|
||||||
|
if len(user) == 1:
|
||||||
|
return "{} {}".format(user[0].first_name, user[0].last_name)
|
||||||
|
else:
|
||||||
|
return '@id' + str(user_id)
|
||||||
|
|
||||||
|
|
||||||
# Обычные сообщения (не команды и не действия)
|
# Обычные сообщения (не команды и не действия)
|
||||||
@labeler.chat_message()
|
@labeler.chat_message()
|
||||||
async def any_message_handler(message: Message):
|
async def any_message_handler(message: Message):
|
||||||
|
|
@ -40,28 +49,31 @@ async def any_message_handler(message: Message):
|
||||||
if bot_user is None:
|
if bot_user is None:
|
||||||
bot_user = (await message.ctx_api.groups.get_by_id()).groups[0]
|
bot_user = (await message.ctx_api.groups.get_by_id()).groups[0]
|
||||||
|
|
||||||
|
ai_message = AiMessage()
|
||||||
|
ai_fwd_message: Optional[AiMessage] = None
|
||||||
|
|
||||||
# Ответ на сообщение бота
|
# Ответ на сообщение бота
|
||||||
if message.reply_message and message.reply_message.from_id == -bot_user.id:
|
if message.reply_message and message.reply_message.from_id == -bot_user.id:
|
||||||
message_text = message.text
|
ai_message.text = message.text
|
||||||
else:
|
else:
|
||||||
# Сообщение содержит @bot_username
|
# Сообщение содержит @bot_username
|
||||||
bot_username_mention = '@' + bot_user.screen_name
|
bot_username_mention = '@' + bot_user.screen_name
|
||||||
if message.text is not None and message.text.find(bot_username_mention) != -1:
|
if message.text is not None and message.text.find(bot_username_mention) != -1:
|
||||||
message_text = message.text.replace(bot_username_mention, bot_user.name)
|
ai_message.text = message.text.replace(bot_username_mention, bot_user.name)
|
||||||
else:
|
else:
|
||||||
# Сообщение содержит [club<bot_id>|<some_name>]
|
# Сообщение содержит [club<bot_id>|<some_name>]
|
||||||
pattern = r"\[club" + str(bot_user.id) + r"\|(.+)]"
|
pattern = r"\[club" + str(bot_user.id) + r"\|(.+)]"
|
||||||
if message.text is not None and re.search(pattern, message.text) is not None:
|
if message.text is not None and re.search(pattern, message.text) is not None:
|
||||||
message_text = re.sub(pattern, r'\1', message.text)
|
ai_message.text = re.sub(pattern, r'\1', message.text)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
user = await message.ctx_api.users.get(user_ids=[message.from_id])
|
if message.reply_message and message.reply_message.text is not None:
|
||||||
if len(user) == 1:
|
ai_fwd_message = (
|
||||||
user_name = "{} {}".format(user[0].first_name, user[0].last_name)
|
AiMessage(user_name=await get_user_name_for_ai(message.ctx_api, message.reply_message.from_id),
|
||||||
else:
|
text=message.reply_message.text))
|
||||||
user_name = '@id' + str(message.from_id)
|
|
||||||
|
|
||||||
|
ai_message.user_name = await get_user_name_for_ai(message.ctx_api, message.from_id)
|
||||||
chat_prompt = chat['ai_prompt']
|
chat_prompt = chat['ai_prompt']
|
||||||
|
|
||||||
global agent
|
global agent
|
||||||
|
|
@ -70,7 +82,7 @@ async def any_message_handler(message: Message):
|
||||||
agent = AiAgent(message.ctx_api.config['openrouter_token'])
|
agent = AiAgent(message.ctx_api.config['openrouter_token'])
|
||||||
|
|
||||||
await message.ctx_api.messages.set_activity(peer_id=chat_id, type='typing')
|
await message.ctx_api.messages.set_activity(peer_id=chat_id, type='typing')
|
||||||
await message.reply(await agent.get_reply(chat_id, chat_prompt, user_name, message_text))
|
await message.reply(await agent.get_reply(chat_id, chat_prompt, ai_message, ai_fwd_message))
|
||||||
|
|
||||||
|
|
||||||
def clear_ai_chat_context(chat_id: int):
|
def clear_ai_chat_context(chat_id: int):
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue