diff --git a/build/lib/evolutionapi/client.py b/build/lib/evolutionapi/client.py index 991d756..7bfdbd7 100644 --- a/build/lib/evolutionapi/client.py +++ b/build/lib/evolutionapi/client.py @@ -1,4 +1,5 @@ import requests +from requests_toolbelt import MultipartEncoder from .exceptions import EvolutionAuthenticationError, EvolutionNotFoundError, EvolutionAPIError from .services.instance import InstanceService from .services.instance_operations import InstanceOperationsService @@ -62,11 +63,43 @@ class EvolutionClient: response = requests.get(url, headers=self._get_headers(instance_token)) return self._handle_response(response) - def post(self, endpoint: str, data: dict = None, instance_token: str = None): - """Faz uma requisição POST.""" - url = self._get_full_url(endpoint) - response = requests.post(url, headers=self._get_headers(instance_token), json=data) - return self._handle_response(response) + def post(self, endpoint: str, data: dict = None, instance_token: str = None, files: dict = None): + url = f'{self.base_url}/{endpoint}' + headers = self._get_headers(instance_token) + + if files: + # Remove o Content-Type do header quando enviando arquivos + if 'Content-Type' in headers: + del headers['Content-Type'] + + # Prepara os campos do multipart + fields = {} + + # Adiciona os campos do data + for key, value in data.items(): + fields[key] = str(value) if not isinstance(value, (int, float)) else (None, str(value), 'text/plain') + + # Adiciona o arquivo + file_tuple = files['file'] + fields['file'] = (file_tuple[0], file_tuple[1], file_tuple[2]) + + # Cria o multipart encoder + multipart = MultipartEncoder(fields=fields) + headers['Content-Type'] = multipart.content_type + + response = requests.post( + url, + headers=headers, + data=multipart + ) + else: + response = requests.post( + url, + headers=headers, + json=data + ) + + return response.json() def put(self, endpoint, data=None): """Faz uma requisição PUT.""" diff --git a/build/lib/evolutionapi/models/message.py b/build/lib/evolutionapi/models/message.py index 739460f..cd4a82a 100644 --- a/build/lib/evolutionapi/models/message.py +++ b/build/lib/evolutionapi/models/message.py @@ -53,28 +53,34 @@ class MediaMessage(BaseMessage): def __init__( self, number: str, - mediatype: str, - mimetype: str, - caption: str, - media: str, - fileName: str, - delay: Optional[int] = None, + media: dict = None, + mediatype: Optional[str] = None, + caption: str = None, + mimetype: str = None, + fileName: str = None, + delay: Optional[Union[int, float, str]] = None, quoted: Optional[QuotedMessage] = None, mentionsEveryOne: Optional[bool] = None, mentioned: Optional[List[str]] = None ): - super().__init__( - number=number, - mediatype=mediatype, - mimetype=mimetype, - caption=caption, - media=media, - fileName=fileName, - delay=delay, - quoted=quoted.__dict__ if quoted else None, - mentionsEveryOne=mentionsEveryOne, - mentioned=mentioned - ) + data = { + 'number': number, + 'mediatype': mediatype, + 'caption': caption, + 'mimetype': mimetype, + 'fileName': fileName, + 'quoted': quoted.__dict__ if quoted else None, + 'mentionsEveryOne': mentionsEveryOne, + 'mentioned': mentioned + } + + if delay is not None: + data['delay'] = delay + + if media and media != {}: + data['media'] = media + + super().__init__(**{k: v for k, v in data.items() if v is not None}) class StatusMessage(BaseMessage): def __init__( diff --git a/build/lib/evolutionapi/services/message.py b/build/lib/evolutionapi/services/message.py index f151259..79efaae 100644 --- a/build/lib/evolutionapi/services/message.py +++ b/build/lib/evolutionapi/services/message.py @@ -1,70 +1,118 @@ from typing import Union, BinaryIO from ..models.message import * +from requests_toolbelt import MultipartEncoder +import mimetypes +import requests class MessageService: def __init__(self, client): self.client = client def send_text(self, instance_id: str, message: TextMessage, instance_token: str): + # Preparar os dados como JSON + data = { + 'number': message.number, + 'text': message.text + } + + if hasattr(message, 'delay') and message.delay is not None: + data['delay'] = message.delay + + # Usar o método post do cliente que já trata JSON corretamente return self.client.post( f'message/sendText/{instance_id}', - data=message.__dict__, + data=data, instance_token=instance_token ) def send_media(self, instance_id: str, message: MediaMessage, instance_token: str, file: Union[BinaryIO, str] = None): - payload = { - 'data': message.__dict__, - 'instance_token': instance_token + # Preparar os dados do formulário + fields = { + 'number': (None, message.number, 'text/plain'), + 'mediatype': (None, message.mediatype, 'text/plain'), + 'mimetype': (None, message.mimetype, 'text/plain'), + 'caption': (None, message.caption, 'text/plain'), + 'fileName': (None, message.fileName, 'text/plain'), } + # Adicionar delay apenas se existir + if hasattr(message, 'delay') and message.delay is not None: + fields['delay'] = (None, str(message.delay), 'text/plain; type=number') + + # Adicionar o arquivo se fornecido if file: if isinstance(file, str): - with open(file, 'rb') as f: - payload['files'] = {'file': f} + mime_type = mimetypes.guess_type(file)[0] or 'application/octet-stream' + fields['file'] = ('file', open(file, 'rb'), mime_type) else: - payload['files'] = {'file': file} - - return self.client.post( - f'message/sendMedia/{instance_id}', - **payload + fields['file'] = ('file', file, 'application/octet-stream') + + # Criar o multipart encoder + multipart = MultipartEncoder(fields=fields) + + # Preparar os headers + headers = self.client._get_headers(instance_token) + headers['Content-Type'] = multipart.content_type + + # Fazer a requisição diretamente + url = f'{self.client.base_url}/message/sendMedia/{instance_id}' + response = requests.post( + url, + headers=headers, + data=multipart ) + + return response.json() def send_ptv(self, instance_id: str, message: dict, instance_token: str, file: Union[BinaryIO, str] = None): - payload = { - 'data': message, - 'instance_token': instance_token - } + fields = {} + + # Adiciona todos os campos do message como text/plain + for key, value in message.items(): + if key == 'delay' and value is not None: + fields[key] = (None, str(value), 'text/plain; type=number') + else: + fields[key] = (None, str(value), 'text/plain') if file: if isinstance(file, str): - with open(file, 'rb') as f: - payload['files'] = {'file': f} + mime_type = mimetypes.guess_type(file)[0] or 'application/octet-stream' + fields['file'] = ('file', open(file, 'rb'), mime_type) else: - payload['files'] = {'file': file} - - return self.client.post( - f'message/sendPtv/{instance_id}', - **payload - ) + fields['file'] = ('file', file, 'application/octet-stream') + + multipart = MultipartEncoder(fields=fields) + headers = self.client._get_headers(instance_token) + headers['Content-Type'] = multipart.content_type + + url = f'{self.client.base_url}/message/sendPtv/{instance_id}' + response = requests.post(url, headers=headers, data=multipart) + return response.json() def send_whatsapp_audio(self, instance_id: str, message: dict, instance_token: str, file: Union[BinaryIO, str] = None): - payload = { - 'data': message, - 'instance_token': instance_token - } + fields = {} + + # Adiciona todos os campos do message como text/plain + for key, value in message.items(): + if key == 'delay' and value is not None: + fields[key] = (None, str(value), 'text/plain; type=number') + else: + fields[key] = (None, str(value), 'text/plain') if file: if isinstance(file, str): - with open(file, 'rb') as f: - payload['files'] = {'file': f} + mime_type = mimetypes.guess_type(file)[0] or 'application/octet-stream' + fields['file'] = ('file', open(file, 'rb'), mime_type) else: - payload['files'] = {'file': file} - - return self.client.post( - f'message/sendWhatsAppAudio/{instance_id}', - **payload - ) + fields['file'] = ('file', file, 'application/octet-stream') + + multipart = MultipartEncoder(fields=fields) + headers = self.client._get_headers(instance_token) + headers['Content-Type'] = multipart.content_type + + url = f'{self.client.base_url}/message/sendWhatsAppAudio/{instance_id}' + response = requests.post(url, headers=headers, data=multipart) + return response.json() def send_status(self, instance_id: str, message: StatusMessage, instance_token: str): return self.client.post( @@ -73,17 +121,39 @@ class MessageService: instance_token=instance_token ) - def send_sticker(self, instance_id: str, message: dict, instance_token: str): - return self.client.post( - f'message/sendSticker/{instance_id}', - data=message, - instance_token=instance_token - ) + def send_sticker(self, instance_id: str, message: dict, instance_token: str, file: Union[BinaryIO, str] = None): + fields = {} + + # Adiciona todos os campos do message como text/plain + for key, value in message.items(): + if key == 'delay' and value is not None: + fields[key] = (None, str(value), 'text/plain; type=number') + else: + fields[key] = (None, str(value), 'text/plain') + + if file: + if isinstance(file, str): + mime_type = mimetypes.guess_type(file)[0] or 'application/octet-stream' + fields['file'] = ('file', open(file, 'rb'), mime_type) + else: + fields['file'] = ('file', file, 'application/octet-stream') + + multipart = MultipartEncoder(fields=fields) + headers = self.client._get_headers(instance_token) + headers['Content-Type'] = multipart.content_type + + url = f'{self.client.base_url}/message/sendSticker/{instance_id}' + response = requests.post(url, headers=headers, data=multipart) + return response.json() def send_location(self, instance_id: str, message: LocationMessage, instance_token: str): + data = message.__dict__.copy() + if 'delay' in data and data['delay'] is not None: + data['delay'] = int(data['delay']) + return self.client.post( f'message/sendLocation/{instance_id}', - data=message.__dict__, + data=data, instance_token=instance_token ) @@ -102,22 +172,34 @@ class MessageService: ) def send_poll(self, instance_id: str, message: PollMessage, instance_token: str): + data = message.__dict__.copy() + if 'delay' in data and data['delay'] is not None: + data['delay'] = int(data['delay']) + return self.client.post( f'message/sendPoll/{instance_id}', - data=message.__dict__, + data=data, instance_token=instance_token ) def send_list(self, instance_id: str, message: ListMessage, instance_token: str): + data = message.__dict__.copy() + if 'delay' in data and data['delay'] is not None: + data['delay'] = int(data['delay']) + return self.client.post( f'message/sendList/{instance_id}', - data=message.__dict__, + data=data, instance_token=instance_token ) def send_buttons(self, instance_id: str, message: ButtonMessage, instance_token: str): + data = message.__dict__.copy() + if 'delay' in data and data['delay'] is not None: + data['delay'] = int(data['delay']) + return self.client.post( f'message/sendButtons/{instance_id}', - data=message.__dict__, + data=data, instance_token=instance_token ) \ No newline at end of file diff --git a/dist/evolutionapi-0.0.4.tar.gz b/dist/evolutionapi-0.0.4.tar.gz deleted file mode 100644 index f9451f6..0000000 Binary files a/dist/evolutionapi-0.0.4.tar.gz and /dev/null differ diff --git a/dist/evolutionapi-0.0.4-py3-none-any.whl b/dist/evolutionapi-0.0.5-py3-none-any.whl similarity index 65% rename from dist/evolutionapi-0.0.4-py3-none-any.whl rename to dist/evolutionapi-0.0.5-py3-none-any.whl index e5087e3..3a29bd5 100644 Binary files a/dist/evolutionapi-0.0.4-py3-none-any.whl and b/dist/evolutionapi-0.0.5-py3-none-any.whl differ diff --git a/dist/evolutionapi-0.0.5.tar.gz b/dist/evolutionapi-0.0.5.tar.gz new file mode 100644 index 0000000..5504967 Binary files /dev/null and b/dist/evolutionapi-0.0.5.tar.gz differ diff --git a/evolutionapi.egg-info/PKG-INFO b/evolutionapi.egg-info/PKG-INFO index f53f99e..3dac2b0 100644 --- a/evolutionapi.egg-info/PKG-INFO +++ b/evolutionapi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: evolutionapi -Version: 0.0.4 +Version: 0.0.5 Summary: Client Python para a API Evolution Home-page: UNKNOWN Author: Davidson Gomes diff --git a/setup.py b/setup.py index c04518a..d4b2a66 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name='evolutionapi', - version='0.0.4', + version='0.0.5', description='Client Python para a API Evolution', author='Davidson Gomes', author_email='contato@agenciadgcode.com',