feat: sending and receiving messages with files, editing text messages

This commit is contained in:
2025-04-02 15:28:22 +04:00
parent 2cdccb33ca
commit 00522da68f
13 changed files with 361 additions and 70 deletions

View File

@@ -1,14 +1,15 @@
from uuid import UUID
import requests
from aiohttp import ClientConnectorError
from fastapi import HTTPException, UploadFile
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from starlette.responses import StreamingResponse
from backend.config import CHAT_CONNECTOR_API_KEY
from backend.config import CHAT_CONNECTOR_API_KEY, CHAT_TELEGRAM_BOT_TOKEN
from external.chat.chat_client import ChatClient
from external.chat.schemas import ExternalCreateGroupRequest, ExternalCreateTopicRequest
from external.chat.schemas import *
from external.kafka.services.producer_service import ProducerService
from models import Message, Chat, MessageStatus, TgGroup, Client, Card
from models import Message, Chat, MessageStatus, TgGroup, Client, Card, MessageFile
from schemas.chat import *
from services.base import BaseService
@@ -161,10 +162,10 @@ class ChatService(BaseService):
messages = (await self.session.scalars(stmt)).all()
return GetMessagesResponse(messages=messages)
async def send_message(self, request: SendMessageRequest) -> SendMessageResponse:
async def send_message(self, request: SendTextMessageRequest) -> SendTextMessageResponse:
chat: Optional[Chat] = await self.session.get(Chat, request.message.chat_id)
if not chat:
return SendMessageResponse(ok=False, message=f'Чат с ID: {request.message.chat_id} не найден')
return SendTextMessageResponse(ok=False, message=f'Чат с ID: {request.message.chat_id} не найден')
message = Message(
text=request.message.text,
@@ -182,7 +183,67 @@ class ChatService(BaseService):
message.id,
)
return SendMessageResponse(ok=ok, message=message)
return SendTextMessageResponse(ok=ok, message=message)
async def repeat_sending_message(
self,
request: RepeatSendingTextMessageRequest,
) -> RepeatSendingTextMessageResponse:
message: Optional[Message] = await self._get_message_by_id(request.message.id)
if not message:
return RepeatSendingTextMessageResponse(ok=False, message=f'Сообщение с ID: {request.message.id} не найдено')
ok, msg = await ProducerService.send_message_to_connector(
request.message.text,
message.chat.tg_group_id,
message.chat.tg_topic_id,
message.id,
)
if ok:
message.status = MessageStatus.sending
await self.session.commit()
return RepeatSendingTextMessageResponse(ok=ok, message=msg)
async def send_messages_with_files(
self,
files: list[UploadFile],
chat_id: int,
caption: str,
) -> LoadMessagesResponse:
chat: Optional[Chat] = await self.session.get(Chat, chat_id)
if not chat:
return SendTextMessageResponse(ok=False, message=f'Чат с ID: {chat_id} не найден')
chat_client = ChatClient(api_key=CHAT_CONNECTOR_API_KEY)
response = await chat_client.send_messages_with_files(
str(chat.tg_group_id),
chat.tg_topic_id,
caption,
files
)
last_message = None
for file_schema in response.files:
file = MessageFile(**file_schema.model_dump())
self.session.add(file)
message = Message(
text='',
created_at=datetime.now(),
chat_id=chat_id,
status=MessageStatus.success,
file=file,
)
last_message = message
self.session.add(message)
if last_message:
last_message.text = caption
await self.session.commit()
return LoadMessagesResponse(ok=response.ok, message=response.message)
async def _get_message_by_id(self, message_id: int) -> Optional[Message]:
stmt = (
@@ -203,7 +264,35 @@ class ChatService(BaseService):
message.chat.tg_group_id,
)
message.is_deleted = True
await self.session.commit()
return DeleteMessageResponse(ok=ok, message=msg)
async def edit_message(self, request: EditMessageRequest) -> EditMessageResponse:
message: Optional[Message] = await self._get_message_by_id(request.message.id)
if not message:
return EditMessageResponse(ok=False, message=f'Сообщение с ID: {request.message.id} не найдено')
ok, msg = await ProducerService.send_message_editing_to_connector(
message.id,
message.tg_message_id,
message.chat.tg_group_id,
request.message.text,
)
return EditMessageResponse(ok=ok, message=msg)
async def get_tg_file(self, file_id: int) -> StreamingResponse:
file: Optional[MessageFile] = await self.session.get(MessageFile, file_id)
if not file:
raise HTTPException(status_code=404, detail=f'Файл с ID {file_id} не найден')
url: str = f'https://api.telegram.org/file/bot{CHAT_TELEGRAM_BOT_TOKEN}/{file.file_path}'
print(f'URL = {url}')
response = requests.get(url, stream=True)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail="Error fetching file")
content_type = response.headers.get("Content-Type", "application/octet-stream")
return StreamingResponse(response.iter_content(chunk_size=8192), media_type=content_type)