From accaa5f2f66f1039ed46f48e718b88d9a38435c7 Mon Sep 17 00:00:00 2001 From: JohntheLi Date: Thu, 4 Jan 2024 12:19:26 -0800 Subject: [PATCH] add download_url option for file attachment (#42) * fastapi_poe client: increase httpx timeout If an httpx session is not passed in, the default timeout of the created session is currently 5 seconds, which is too short for long LLM requests. Make the default 120 seconds instead. User can pass in their own httpx session if they wish to set a custom timeout. Also, make the error log print repr(e) as httpx.ReadTimeout did not have a message body. So at least the exception type will be printed. * release 0.0.23 increase default timeout and allow passing httpx session into get_bot_response() * PoeBot: default no generated suggested replies to match with the documentation, Poe generated suggested replies should be disabled by default. * add function for file attachments function to call the new file attachment endpoint. * add function for file attachments function to call the new file attachment endpoint. * update to 0.0.26 * add optional download_url parameter for file attachment * fix some typings * remove HTTPException type to fix type check * try fixing error handler --- src/.DS_Store | Bin 0 -> 6148 bytes src/fastapi_poe/base.py | 53 ++++++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 src/.DS_Store diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b4ed6e50a972e12396a7c4dcfcf92165dd8d6a0f GIT binary patch literal 6148 zcmeHKO;6iE5SC*d%SO8gCRk%^`~9GyOyT zCH*__W_MFmgj2Er4@^Xw~D^CKHTWzP}Q zm{J-bnw4r9c!>(|yKB-{im9Ly@$vnQK4<18$xMO@{yaXy_wKDBTgysj#n`icC*v$F z%1-Bxs%_NYY;FZxK{NOgeK)hHjLT`!k0+OWbY@JJEb}-yPe-#s>)j`lmvNepCYF#6 zM<}_vNb{kY_02RN7M2^iiJ%cQ2Cbd>ym#1b>w{i*(bn@1y-r)dKR8@08o~DN{?X~+ zM|PW=JA416@XcC#>v0LckgU<9g&r%1 zj!w!qAIe`@`3^ AsyncIterable[Union[PartialResponse, ServerSentEvent]]: @@ -111,11 +114,11 @@ def __init__(self): self.file_attachment_lock = asyncio.Lock() async def post_message_attachment( - self, message_id, file_data, filename, access_key + self, access_key, message_id, download_url=None, file_data=None, filename=None ): task = asyncio.create_task( self._make_file_attachment_request( - message_id, file_data, filename, access_key + access_key, message_id, download_url, file_data, filename ) ) async with self.file_attachment_lock: @@ -124,19 +127,30 @@ async def post_message_attachment( self.pending_file_attachments[message_id] = files_for_message async def _make_file_attachment_request( - self, message_id, file_data, filename, access_key + self, access_key, message_id, download_url=None, file_data=None, filename=None ): url = "https://www.quora.com/poe_api/file_attachment_POST" async with httpx.AsyncClient(timeout=120) as client: try: - files = {"file": (filename, file_data)} - data = {"message_id": message_id} headers = {"Authorization": f"{access_key}"} - - request = httpx.Request( - "POST", url, files=files, data=data, headers=headers - ) + if download_url: + if file_data or filename: + raise InvalidParameterError( + "Cannot provide filename or file_data if download_url is provided." + ) + data = {"message_id": message_id, "download_url": download_url} + request = httpx.Request("POST", url, data=data, headers=headers) + elif file_data and filename: + data = {"message_id": message_id} + files = {"file": (filename, file_data)} + request = httpx.Request( + "POST", url, files=files, data=data, headers=headers + ) + else: + raise InvalidParameterError( + "Must provide either download_url or file_data and filename." + ) response = await client.send(request) if response.status_code != 200: @@ -147,15 +161,18 @@ async def _make_file_attachment_request( return response except httpx.HTTPError: logger.error("An HTTP error occurred when attempting to attach file") + raise async def _process_pending_attachment_requests(self, message_id): try: await asyncio.gather(*self.pending_file_attachments.get(message_id, [])) except Exception: logger.error("Error processing pending attachment requests") - # clear the pending attachments for the message - async with self.file_attachment_lock: - self.pending_file_attachments.pop(message_id, None) + raise + finally: + # clear the pending attachments for the message + async with self.file_attachment_lock: + self.pending_file_attachments.pop(message_id, None) @staticmethod def text_event(text: str) -> ServerSentEvent: @@ -256,7 +273,11 @@ async def handle_query( except Exception as e: logger.exception("Error responding to query") yield self.error_event(repr(e), allow_retry=False) - await self._process_pending_attachment_requests(request.message_id) + try: + await self._process_pending_attachment_requests(request.message_id) + except Exception as e: + logger.exception("Error processing pending attachment requests") + yield self.error_event(repr(e), allow_retry=False) yield self.done_event() @@ -327,7 +348,7 @@ def make_app( ) -> FastAPI: """Create an app object. Arguments are as for run().""" app = FastAPI() - app.add_exception_handler(RequestValidationError, exception_handler) + app.add_exception_handler(RequestValidationError, http_exception_handler) global auth_key auth_key = _verify_access_key(