|
|
@@ -1,67 +1,39 @@
|
|
|
import asyncio
|
|
|
-import base64
|
|
|
import logging
|
|
|
import textwrap
|
|
|
-from io import BytesIO
|
|
|
-from typing import AsyncGenerator, Literal
|
|
|
+from typing import AsyncGenerator, Literal, Optional
|
|
|
|
|
|
-from aiogram import Bot
|
|
|
-from aiogram.types import Message
|
|
|
-
|
|
|
-from anonflow.config import Config
|
|
|
-from anonflow.services.transport.events import (
|
|
|
- Events,
|
|
|
- ModerationDecisionEvent,
|
|
|
- ModerationStartedEvent
|
|
|
+from anonflow.services.transport.results import (
|
|
|
+ Results,
|
|
|
+ ModerationDecisionResult,
|
|
|
+ ModerationStartedResult
|
|
|
)
|
|
|
|
|
|
from .planner import ModerationPlanner
|
|
|
|
|
|
|
|
|
class ModerationExecutor:
|
|
|
- def __init__(
|
|
|
- self,
|
|
|
- bot: Bot,
|
|
|
- config: Config,
|
|
|
- planner: ModerationPlanner,
|
|
|
- ):
|
|
|
+ def __init__(self, planner: ModerationPlanner):
|
|
|
self._logger = logging.getLogger(__name__)
|
|
|
|
|
|
- self.bot = bot
|
|
|
- self.config = config
|
|
|
-
|
|
|
self.planner = planner
|
|
|
self.planner.set_functions(self.moderation_decision)
|
|
|
|
|
|
def moderation_decision(self, status: Literal["approve", "reject"], reason: str):
|
|
|
moderation_map = {"approve": True, "reject": False}
|
|
|
- return ModerationDecisionEvent(approved=moderation_map.get(status.lower(), False), reason=reason)
|
|
|
+ return ModerationDecisionResult(is_approved=moderation_map.get(status.lower(), False), reason=reason)
|
|
|
moderation_decision.description = textwrap.dedent( # type: ignore
|
|
|
"""
|
|
|
- Processes a message with a moderation decision by status and explanation.
|
|
|
+ Processes a message with a moderation decision by status and reason.
|
|
|
This function must be called whenever there is no exact user request or no other available function
|
|
|
- matching the user's intent. Status must be either "APPROVE" if the message is allowed, or "REJECT" if it should be blocked.
|
|
|
+ matching the user's intent. Status must be either "approve if the message is allowed, or "reject" if it should be blocked.
|
|
|
"""
|
|
|
).strip()
|
|
|
|
|
|
- async def _get_b64image(self, message: Message):
|
|
|
- if message.photo:
|
|
|
- photo = message.photo[-1]
|
|
|
- file = await self.bot.get_file(photo.file_id)
|
|
|
- if file:
|
|
|
- buffer = BytesIO()
|
|
|
- await self.bot.download(file, buffer)
|
|
|
- buffer.seek(0)
|
|
|
- return (base64.b64encode(buffer.read())).decode()
|
|
|
-
|
|
|
- async def process_message(self, message: Message) -> AsyncGenerator[Events, None]:
|
|
|
- yield ModerationStartedEvent()
|
|
|
+ async def process(self, text: Optional[str] = None, image: Optional[str] = None) -> AsyncGenerator[Results, None]:
|
|
|
+ yield ModerationStartedResult()
|
|
|
|
|
|
- image = await self._get_b64image(message)
|
|
|
- functions = await self.planner.plan(
|
|
|
- (message.text or message.caption),
|
|
|
- f"data:image/jpeg;base64,{image}" if image else None
|
|
|
- )
|
|
|
+ functions = await self.planner.plan(text, image)
|
|
|
function_names = self.planner.get_function_names()
|
|
|
|
|
|
for func in functions:
|