add notify for chat

This commit is contained in:
harold 2025-02-08 11:41:20 +05:00
parent e32ac46898
commit 9e2dcaee53
10 changed files with 129 additions and 10 deletions

View File

@ -26,6 +26,7 @@ CREATE TABLE tg_messages (
CREATE TABLE successed ( CREATE TABLE successed (
id BIGSERIAL PRIMARY KEY UNIQUE, id BIGSERIAL PRIMARY KEY UNIQUE,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
chat_id BIGINT NOT NULL REFERENCES tgchats(id) ON DELETE CASCADE, reason TEXT NOT NULL,
chat_id UUID NOT NULL REFERENCES tgchats(slice_id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT NOW() NOT NULL created_at TIMESTAMP DEFAULT NOW() NOT NULL
); );

View File

@ -1,8 +1,17 @@
from sqlalchemy.orm import Mapped, mapped_column from typing import TYPE_CHECKING
from sqlalchemy.orm import Mapped, relationship
from src.core.database import Base from src.core.database import Base
if TYPE_CHECKING:
from src.core.database import TgMessage
class TgChat(Base): class TgChat(Base):
chat_type: Mapped[str] chat_type: Mapped[str]
title: Mapped[str] title: Mapped[str]
message_relationship: Mapped[list["TgMessage"]] = relationship(
backref="tgchat_relationship",
)

View File

@ -1,10 +1,15 @@
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING
from uuid import UUID
from sqlalchemy import ForeignKey, func from sqlalchemy import ForeignKey, func
from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.orm import Mapped, mapped_column, relationship
from src.core.database import Base from src.core.database import Base
if TYPE_CHECKING:
from src.core.database import User, TgChat
class Success(Base): class Success(Base):
__tablename__ = 'successed' __tablename__ = 'successed'
@ -16,10 +21,18 @@ class Success(Base):
user_id: Mapped[str] = mapped_column( user_id: Mapped[str] = mapped_column(
ForeignKey('users.id', ondelete='CASCADE'), ForeignKey('users.id', ondelete='CASCADE'),
) )
chat_id: Mapped[int] = mapped_column( slice_id: Mapped[UUID] = mapped_column(
ForeignKey('tgchats.id', ondelete='CASCADE'), ForeignKey('tgchats.slice_id', ondelete='CASCADE'),
) )
reason: Mapped[str]
created_at: Mapped[datetime] = mapped_column( created_at: Mapped[datetime] = mapped_column(
default=datetime.utcnow, default=datetime.utcnow,
server_default=func.now() server_default=func.now()
) )
user_relationship: Mapped["User"] = relationship(
backref="success_relationship"
)
chat_relationship: Mapped["TgChat"] = relationship(
backref="success_relationship"
)

View File

@ -5,6 +5,7 @@ from src.core.common.constants import PydanticEnvPrefixEnum, EnvFileLocation, En
from src.core.settings.database import DatabaseSettings from src.core.settings.database import DatabaseSettings
from src.core.settings.gemini import GeminiSettings from src.core.settings.gemini import GeminiSettings
from src.core.settings.groq import GroqSettings from src.core.settings.groq import GroqSettings
from src.core.settings.notify import NotifySettings
from src.core.settings.rabbitmq import RabbitmqSettings from src.core.settings.rabbitmq import RabbitmqSettings
from src.core.settings.redis import RedisSettings from src.core.settings.redis import RedisSettings
@ -23,6 +24,8 @@ class Settings(BaseSettings):
POSTGRES: DatabaseSettings POSTGRES: DatabaseSettings
NOTIFY: NotifySettings = NotifySettings()
GROQ: GroqSettings GROQ: GroqSettings
GEMINI: GeminiSettings GEMINI: GeminiSettings
REDIS: RedisSettings REDIS: RedisSettings

View File

@ -0,0 +1,5 @@
from pydantic import BaseModel
class NotifySettings(BaseModel):
CHAT_ID: int = -4781950241

View File

@ -2,13 +2,17 @@ import uuid
from pyrogram.types.user_and_chats import User as PyroUser, Chat as PyroChat from pyrogram.types.user_and_chats import User as PyroUser, Chat as PyroChat
from src.core.database import TgChat, User from src.core.database import TgChat, User, TgMessage
from src.core.database.successes import Success
from src.core.rabbitmq.connect import message_handler_publisher from src.core.rabbitmq.connect import message_handler_publisher
from src.core.redis_helper.redis_connect import redis_client from src.core.redis_helper.redis_connect import redis_client
from src.core.settings.base import settings
from src.core.tg_service.constants import MESSAGE_CHANG_SIZE from src.core.tg_service.constants import MESSAGE_CHANG_SIZE
from src.core.tg_service.schemas import UserFromMessageSchema, MessagesForSendToWorkersSchema, MessageFromChatSchema from src.core.tg_service.schemas import UserFromMessageSchema, MessagesForSendToWorkersSchema, MessageFromChatSchema
from src.core.database.connect import db_helper from src.core.database.connect import db_helper
from src.core.tg_service import crud as tg_crud from src.core.tg_service import crud as tg_crud
from src.core.tg_service.utils import create_and_format_message
from src.main import app
async def check_user_exists( async def check_user_exists(
@ -88,4 +92,21 @@ async def check_chunk_state_and_publish(
data[chat_id].append(message_schema) data[chat_id].append(message_schema)
async def notify_for_success(
messages: list[TgMessage],
chat: TgChat,
success_reason: Success,
user_model: User,
) -> None:
message = create_and_format_message(
messages=messages,
reason=success_reason.reason,
user_model=user_model,
chat=chat,
)
await app.send_message(
chat_id=settings.NOTIFY.CHAT_ID,
message=message,
parse_mode="Markdown",
)

View File

@ -1,6 +1,9 @@
from pyrogram.types import Message from pyrogram.types import Message
from pyrogram.enums import ChatType from pyrogram.enums import ChatType
from src.core.database import TgMessage, User, TgChat
def check_message_condition( def check_message_condition(
message: Message, message: Message,
) -> bool: ) -> bool:
@ -11,3 +14,28 @@ def check_message_condition(
) )
return all(conditions) return all(conditions)
def create_and_format_message(
messages: list[TgMessage],
reason: str,
chat: TgChat,
user_model: User,
) -> str:
if user_model.username:
user_link = f"{user_model.username}](tg://user?id={user_model.id})"
else:
user_link = f"ID: {user_model.id}"
messages_text = "\n".join(
f"{msg.message_time.isoformat()}: {msg.text}\n" for msg in messages
)
chat_link = f"https://t.me/c/{str(chat.id)[4:]}" if str(chat.id).startswith(
"-100") else f"https://t.me/{chat.id}"
return f"""🔥 *Найдена успешка!*
👤 *Пользователь:* {user_link}
🐩 *Чат*: [{chat.title}]({chat_link})
📌 *Причина:* {reason}
📝 *Диалог:* {messages_text}
"""

View File

@ -1,6 +1,10 @@
from sqlalchemy import insert from uuid import UUID
from sqlalchemy import insert, select
from sqlalchemy.orm import selectinload, joinedload
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from src.core.database import TgMessage, TgChat
from src.core.workers.schemas import ResponseFromGeminiSchema from src.core.workers.schemas import ResponseFromGeminiSchema
from src.core.database.successes import Success from src.core.database.successes import Success
@ -19,3 +23,21 @@ async def bulk_create_success_reasons(
) )
await session.execute(stmt) await session.execute(stmt)
await session.commit() await session.commit()
async def get_messages_by_slice_id(
session: AsyncSession,
slice_id: UUID
) -> Success:
stmt = (
select(Success)
.options(
joinedload(Success.user_relationship),
joinedload(Success.chat_relationship)
.selectinload(TgChat.message_relationship)
)
.where(Success.slice_id == slice_id)
)
return await session.scalar(stmt)

View File

@ -4,6 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from faststream import Depends from faststream import Depends
from src.core.tg_service.service import notify_for_success
from src.core.workers.schemas import ResponseFromGeminiSchema from src.core.workers.schemas import ResponseFromGeminiSchema
from src.core.database.connect import db_helper from src.core.database.connect import db_helper
from src.core.rabbitmq.connect import success_gemini_subscriber from src.core.rabbitmq.connect import success_gemini_subscriber
@ -20,5 +21,21 @@ async def create_success_record(
session=session, session=session,
) )
for success_message in message.success:
success_mod_with_relation = await workers_crud.get_messages_by_slice_id(
session=session,
slice_id=success_message.slice_id,
)
await notify_for_success(
messages=success_mod_with_relation.chat_relationship.message_relationship,
chat=success_mod_with_relation.chat_relationship,
user_model=success_mod_with_relation.user_relationship,
success_reason=success_mod_with_relation,,
)

View File

@ -1,9 +1,9 @@
from pydantic import BaseModel, PositiveInt, NegativeInt from pydantic import BaseModel, PositiveInt, NegativeInt, UUID4
class SuccessChatFromAiSchema(BaseModel): class SuccessChatFromAiSchema(BaseModel):
user_id: PositiveInt | None user_id: PositiveInt | None
chat_id: NegativeInt | None slice_id: UUID4 | None
reason: str | None reason: str | None