Message Boards Message Boards

sendPhoto using TelegramBot (exporting to multy-part form data format)

Posted 6 years ago

I created a telegram-bot and I execute requests to the telegram bot API from Mathematica. You can find full API documentation here. I have a problem with sending image from computer or RAM. I try send photo using this code:

$token = <token> (* string -  bot token from @BotFather *)
$chat = <chat_id> (* string - allowed chat id *)

$api = StringTemplate["https://api.telegram.org/bot`token`"][<|"token" -> $token|>]
$url = URLBuild[{$api, "sendPhoto"}]

dataString = ExportString[Plot[Sin[x], {x, 1, 4}, ImageSize->Tiny], "JPEG"]; 

body = StringTemplate[
"
--WMAsrf456BGe4h
Content-Disposition: form-data; name=\"chat_id\"

`chat_id`
--WMAsrf456BGe4h
Content-Disposition: form-data; name=\"photo\";filename=\"photo.jpg\"
Content-Type: image/jpeg

`data`
--WMAsrf456BGe4h"
]; (* https://en.wikipedia.org/wiki/MIME#Multipart_messages *)

request[] := 
HTTPRequest[$url,
<|
Method -> "POST", 
"ContentType" -> "multipart/form-data; boundary=WMAsrf456BGe4h", 
"Headers" -> {
"Connection" -> "keep-alive"
}, 
"Body" -> body[<|"chat_id" -> $chat, "data" -> dataString|>]
|>
]

response = URLRead[request[]]

(* Out[..] := HTTPResponse[<<504>>] *)

response["Body"]
(* Out[..] := "<html>
<head><title>504 Gateway Time-out</title></head>
<body bgcolor=\"white\">
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.12.2</center>
</body>
</html>" *)

how to send an image?

POSTED BY: Kirill Belov
6 Replies
Posted 6 years ago

Try

dataString = ExportString[ExportString[Plot[Sin[x], {x, 1, 4}, ImageSize->Tiny], "JPEG"], "Base64"];
POSTED BY: Bob Tieman

I had a brief look at the API linked. At this time I can only give you pointers to your issues.

Content-Length is in bytes (should give value in bytes, so server will know when to stop).

I believe the Image needs to be base64 (ASCII) encoded.

500 level errors indicate that some processing went wrong on the server side. But I think this is due to content length and possible image encoding.

POSTED BY: Hans Michel
Posted 6 years ago

The length in bytes is right. If you delete this header (content-length) then the result will not unchanged. At the moment there is no difference with the use of base64 and without it. Both of ways returns status code 400 and the message "Bad Request: there is no photo in the request"

POSTED BY: Kirill Belov
Posted 6 years ago

I did not manage to solve the problem. But I looked at the full text of the query, which is generated by libraries in other languages. I managed almost exactly to repeat everything, but still I can not send the image.

Request:

request := 
HTTPRequest["https://api.telegram.org/bot<token>/sendPhoto", 
  <|
    Method -> "POST", 
    "ContentType" -> "multipart/form-date; boundary=QWERTYUIOPASDFGHJKLZXCVBNM", 
    "Headers" -> {
      "Accept" -> "application/json, applcation/xml, text/json, text/x-json, text/javascript, text/xml", 
      "Host" -> "api.telegram.org", 
      "Content-Length" -> ToString[StringLength[multipartData]], 
      "Accept-Encoding" -> "gzip, deflate"
    }, 
    "Body" -> multipartData 
  |>
] 

And request-body. important: here the \r\n is used instead of the \n:

multipartData  := 
StringJoin[{
"\r\n", 
"--QWERTYUIOPASDFGHJKLZXCVBNM", "\r\n", 
"Content-Disposition: form-data; name=\"chat_id\"", "\r\n", "\r\n", 

"490138492", "\r\n", 
"--QWERTYUIOPASDFGHJKLZXCVBNM", "\r\n",  
"Content-Disposition: form-data; name=\"photo\"; filename=\"photo-1.png\"", "\r\n", 
"Content-Type: application/octet-stream", "\r\n", "\r\n", 

ExportString[Plot[Sin[x], {x, 1, 2}, ImageSize -> 5], "PNG"], "\r\n", 
"--QWERTYUIOPASDFGHJKLZXCVBNM" , "\r\n"

}]

And executing the request:

URLExecute[request]

(* Out[..] := {ok->False,error_code->400,description->Bad Request: there is no photo in the request} *)

Last result the better than response with status-code 504. I indicated all headers and parameters by hand. Why could not the picture upload?

POSTED BY: Kirill Belov

If you look into the Details section of HTTPRequest there is a section starting with "The setting for "Body" can have the following forms:"

Among the possible forms there is one that includes explicit File heads, have you tried that?

A bit further down there is even an example:

image = FindFile["ExampleData/Ocelot.jpg"];
req = HTTPRequest[url, <|"Body" -> {"image" -> File[image]}|>];
URLRead[req, "Body"]
POSTED BY: Carlo Barbieri
Posted 6 years ago

Thank you, yes, I tried to do so and, strange as it may seem, it worked. But this works only for a file on disk. Solution - create a temporary file, but how to send it from RAM, I still do not understand.

POSTED BY: Kirill Belov
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract