Skip to content

Commit e967811

Browse files
committed
v0.2.0
Telegram bot API 8.2, OpenAI API, xAI API, and ElevenLabs API
1 parent d90c165 commit e967811

File tree

10 files changed

+2365
-141
lines changed

10 files changed

+2365
-141
lines changed

.project

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,4 @@
1414
<natures>
1515
<nature>com.wolfram.eclipse.MEET.SimpleMathematicaNature</nature>
1616
</natures>
17-
<linkedResources>
18-
<link>
19-
<name>TelegramBotAPI_2024_01_06.nb</name>
20-
<type>1</type>
21-
<location>D:/Google Drive/Data Part2/Work/Business/TBpack startup/Conference Program Bot/Promotions/QLIN 9-14 Jan 2024/TelegramBotAPI_2024_01_06.nb</location>
22-
</link>
23-
</linkedResources>
2417
</projectDescription>

PacletInfo.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
(* Paclet Info File *)
22

3-
(* created 2024/06/13*)
3+
(* created 2025/01/16*)
44

55
Paclet[
66
Name -> "TelegramBotAPI",
7-
Version -> "0.1.0",
7+
Version -> "0.2.0",
88
MathematicaVersion -> "10.0+",
99
Description -> "Telegram Bot API for Wolfram Language",
1010
Creator -> "Vasil Saroka <40.ovasil@gmail.com>",
@@ -23,7 +23,7 @@
2323
URL -> "https://github.com/vasilsaroka/TelegramBotAPI",
2424
Location -> "https://github.com/vasilsaroka/TelegramBotAPI",
2525
Support -> "https://t.me/vasilsaroka",
26-
UUID -> "TelegramBotAPI-3d5c6cae-ef0c-46e6-92e3-cc413a15ba1b",
26+
UUID -> "TelegramBotAPI-4d202827-c2d9-4565-b673-6acbcf16658d",
2727
Extensions ->
2828
{
2929
{"Kernel", Context -> "TelegramBotAPI`"}

TelegramBotAPI/AvailableMethods.m

Lines changed: 1193 additions & 48 deletions
Large diffs are not rendered by default.

TelegramBotAPI/AvailableTypes.m

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
(* Wolfram Language Package *)
22

33
BeginPackage["TelegramBotAPI`AvailableTypes`"]
4+
5+
Unprotect[Evaluate[$Context<>"*"]];
6+
7+
48
(* Exported symbols added here with SymbolName::usage *)
5-
InlineKeyboardMarkup::usage = "InlineKeyboardMarkup[\!\(\*RowBox[{StyleBox[\"arrayofojbects\",\"TI\"]}]\)] represents array of button rows, each represented by an array of \!\(\*StyleBox[\"InlineKeyboardButton\",\"TI\"]\) objects.";
9+
InlineKeyboardMarkup::usage = "InlineKeyboardMarkup[\!\(\*RowBox[{StyleBox[\"arrayofojbects\",\"TI\"]}]\)] represents array of button rows, each represented by an array of \!\(\*StyleBox[\"InlineKeyboardButton\",\"TI\"]\) objects.
10+
\!\(\*TemplateBox[{\"Read on Telegram Bot API webpage\", \"https://core.telegram.org/bots/api#inlinekeyboardmarkup\"}, \"HyperlinkURL\"]\)";
611
InlineKeyboardButton::usage = "InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"]}]\)] is an object representing one button of an inline keyboard. It must use exactly one of the optional fields.
712
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" , StyleBox[\"options\",\"TI\"]}]\)] is a button of an inline keyboard with specified \!\(\*StyleBox[\"options\",\"TI\"]\).
813
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"URL\", \"\[Rule]\", StyleBox[\"url\",\"TI\"]}]\)] is a button with specified HTTP or tg:// \!\(\*StyleBox[\"url\",\"TI\"]\) to be opened when the button is pressed; for instance, tg://user?id=<user_id> if allowed by user's privacy settings.
@@ -13,7 +18,8 @@
1318
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"SwitchInlineQueryCurrentChat\", \"\[Rule]\", StyleBox[\"string\",\"TI\"]}]\)] is a button inserting bot's name together with \!\(\*StyleBox[\"string\",\"TI\"]\) inline query in the input field of the current chat.
1419
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"SwitchInlineQueryChosenChat\", \"\[Rule]\", StyleBox[\"SwitchInlineQueryChosenChat\",\"TI\"]}]\)] is a button prompting the user to select one of their chats of the type specified in \!\(\*StyleBox[\"SwitchInlineQueryChosenChat\",\"TI\"]\) object.
1520
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"CallbackGame\", \"\[Rule]\", StyleBox[\"CallbackGame\",\"TI\"]}]\)] is a button launching the game described in \!\(\*StyleBox[\"CallbackGame\",\"TI\"]\) object.
16-
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"Pay\", \"\[Rule]\", StyleBox[\"True\",\"TI\"]}]\)] is a button representing a Pay button.";
21+
InlineKeyboardButton[\!\(\*RowBox[{StyleBox[\"text\",\"TI\"], \",\" ,\"Pay\", \"\[Rule]\", StyleBox[\"True\",\"TI\"]}]\)] is a button representing a Pay button.
22+
\!\(\*TemplateBox[{\"Read on Telegram Bot API webpage\", \"https://core.telegram.org/bots/api#inlinekeyboardbutton\"}, \"HyperlinkURL\"]\)";
1723

1824

1925
(* Options *)
@@ -45,42 +51,34 @@
4551
Pay -> False
4652
};
4753
(* warnings *)
48-
InlineKeyboardButton::bytelim =
54+
InlineKeyboardButton::warn =
4955
"The CallbackData string size `1` is too large. It must be limited to 1-64 bytes. In Mathematica the string size determined by ByteCount can be `2` bytes.";
5056
InlineKeyboardButton[text_?StringQ,OptionsPattern[]] := Block[
51-
{
52-
url = OptionValue[URL],
53-
callbackdata = OptionValue[CallbackData],
54-
webapp = OptionValue[WebApp],
55-
loginurl = OptionValue[LoginURL],
56-
switchinlinequery = OptionValue[SwitchInlineQuery],
57-
switchinlinequerycurrentchat = OptionValue[SwitchInlineQueryCurrentChat],
58-
switchinlinequerychosenchat = OptionValue[SwitchInlineQueryChosenChat],
59-
callbackgame = OptionValue[CallbackGame],
60-
pay = OptionValue[Pay],
61-
57+
{
6258
callbackdatabytesize,
6359
callbackdatabytelimit = 88
6460
},
65-
callbackdatabytesize = ByteCount[callbackdata];
61+
callbackdatabytesize = ByteCount[OptionValue[CallbackData]];
6662
If[callbackdatabytesize > callbackdatabytelimit,
67-
Message[InlineKeyboardButton::bytelim, callbackdatabytesize,
63+
Message[InlineKeyboardButton::warn, callbackdatabytesize,
6864
callbackdatabytelimit]];
6965
{
7066
"text" -> text,
71-
"url" -> url,
72-
"callback_data" -> callbackdata,
73-
"web_app" -> webapp,
74-
"login_url" -> loginurl,
75-
"switch_inline_query" -> switchinlinequery,
76-
"switch_inline_query_current_chat" -> switchinlinequerycurrentchat,
77-
"switch_inline_query_chosen_chat" -> switchinlinequerychosenchat,
78-
"callback_game" -> callbackgame,
79-
"pay" -> pay
67+
"url" -> OptionValue[URL],
68+
"callback_data" -> OptionValue[CallbackData],
69+
"web_app" -> OptionValue[WebApp],
70+
"login_url" -> OptionValue[LoginURL],
71+
"switch_inline_query" -> OptionValue[SwitchInlineQuery],
72+
"switch_inline_query_current_chat" -> OptionValue[SwitchInlineQueryCurrentChat],
73+
"switch_inline_query_chosen_chat" -> OptionValue[SwitchInlineQueryChosenChat],
74+
"callback_game" -> OptionValue[CallbackGame],
75+
"pay" -> OptionValue[Pay]
8076
}
8177
](* end Block *);
8278
SyntaxInformation[InlineKeyboardButton] = {"ArgumentsPattern" -> {_,OptionsPattern[]}};
8379

8480
End[] (* End Private Context *)
8581

82+
(Attributes[#] = {Protected, ReadProtected}) & /@ Names[Evaluate[$Context<>"*"]]
83+
8684
EndPackage[]

TelegramBotAPI/ElevenLabs.m

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
(* Wolfram Language Package *)
2+
3+
BeginPackage["TelegramBotAPI`ElevenLabs`"]
4+
5+
Unprotect[Evaluate[$Context<>"*"]];
6+
7+
8+
(* Exported symbols added here with SymbolName::usage *)
9+
(* Usage messages: use here String Representation of Boxes to get formatting similar to built-in functions *)
10+
(* Functions*)
11+
textToSpeechXI::usage = "textToSpeechXI[\!\(\*RowBox[{StyleBox[\"voiceid\",\"TI\"],\",\", StyleBox[\"text\",\"TI\"]}]\)] converts \!\(\*StyleBox[\"text\",\"TI\"]\) to speech using voice specified by \!\(\*StyleBox[\"voiceid\",\"TI\"]\). Use VoicesXI[] to list all the available voices.
12+
textToSpeechXI[\!\(\*RowBox[{StyleBox[\"voiceid\",\"TI\"],\",\", StyleBox[\"text\",\"TI\"],\",\" , StyleBox[\"options\",\"TI\"]}]\)] converts \!\(\*StyleBox[\"text\",\"TI\"]\) to speech applying specified \!\(\*StyleBox[\"options\",\"TI\"]\) given as a sequence of rules.
13+
textToSpeechXI[\!\(\*RowBox[{\"\[Ellipsis]\", \",\" , \"\\\"enable_logging''\", \"\[Rule]\", StyleBox[\"value\",\"TI\"]}]\)] returns the response applying the specified \!\(\*StyleBox[\"value\",\"TI\"]\) to the chosen option. N.B. Option names are given as strings.
14+
The options to choose from:
15+
\"enable_logging\": When set to False full privacy mode will be used for the request. May only be used by enterprise customers; defaults to True.
16+
\"output_format\": The output format of the generated audio.; defaults to \"mp3_44100_128\".
17+
\"model_id\": Identifier of the model to be used. Use ModelsXI[] to list the models. The model needs to have support for text to speech; defaults to \"eleven_monolingual_v1\".
18+
\"language_code\": Language code (ISO 639-1) used to enforce a language for the model. (currently only Turbo v2.5); defaults to Null.
19+
\"voice_settings\": Voice settings overriding stored setttings for the given voice; defaults to {\"stability\" \[Rule] 0.5, \"similarity_boost\" \[Rule] 0.8, \"style\" \[Rule] 0.0, \"use_speaker_boost\" \[Rule] True}.
20+
\"pronunciation_dictionary_locators\": A list of pronunciation dictionary locators {\"id\", \"version_id\"} to be applied to the text (up to 3 per request); defaults to an empty list {}.
21+
\"seed\": If specified, the system will try to sample deterministically, though determinism is not guaranteed. Must be integer between 0 and 4294967295; defaults to Null.
22+
\"previous_text\": The text that came before the current request (useful for concatenating multiple generations); defaults to Null.
23+
\"next_text\": The text that comes after the current request. (useful for concatenating multiple generations); defaults to Null.
24+
\"previous_request_ids\": A list of maximum 3 \"request_id\" of the samples that were generated before this generation. If used, \"previous_text\" is ignored; defaults to {}.
25+
\"next_request_ids\": A list of maximum 3 \"request_id\" of the samples that were generated before this generation. If used, \"next_text\" is ignored; defaults to {}.
26+
\"apply_text_normalization\": Controls text normalization (e.g., spelling out numbers) with three modes: \"auto\", \"on\", and \"off\". Cannot be turned on for \"eleven_turbo_v2_5\" model.; defaults to \"auto\".
27+
\"Directory\": The directory to save generated speech; defaults to $TemporaryDirectory.
28+
\"FileName\": The file name to be given to the saved speech; defaults to \"voice\".
29+
\"Format\": The format to which the speech is to be exported. It is an extension of \"FileName\"; defaults to \"mp3\".
30+
\"APIKey\": Your \!\(\*TemplateBox[{\"authentication key\", \"https://elevenlabs.io/docs/api-reference/authentication\"}, \"HyperlinkURL\"]\) to access ElevenLabs API; defaults to $XILabsAPIKey.
31+
\!\(\*TemplateBox[{\"Read on ElevenLabs API webpage\", \"https://elevenlabs.io/docs/api-reference/text-to-speech/convert\"}, \"HyperlinkURL\"]\)";
32+
33+
VoicesXI::usage = "VoicesXI[] lists the available by default voices accessing the end point \!\(\*StyleBox[\"https://api.elevenlabs.io/v1/voices\",Rule[Background, RGBColor[1, 0.85`, 0.85`]]]\).
34+
VoicesXI[\!\(\*RowBox[{\"\\\"APIKey''\", \"\[Rule]\", StyleBox[\"string\",\"TI\"]}]\)] returns the response applying the specified \!\(\*StyleBox[\"string\",\"TI\"]\) to the chosen option. N.B. Option names are given as strings.
35+
The options to choose from:
36+
\"APIKey\": Your \!\(\*TemplateBox[{\"authentication key\", \"https://elevenlabs.io/docs/api-reference/authentication\"}, \"HyperlinkURL\"]\) to access ElevenLabs API; defaults to $XILabsAPIKey.
37+
\!\(\*TemplateBox[{\"Read on ElevenLabs API webpage\", \"https://elevenlabs.io/docs/api-reference/text-to-speech/convert\"}, \"HyperlinkURL\"]\)";
38+
39+
ModelsXI::usage = "ModelsXI[] lists the available by default models accessing the end point \!\(\*StyleBox[\"https://api.elevenlabs.io/v1/models\",Rule[Background, RGBColor[1, 0.85`, 0.85`]]]\).
40+
ModelsXI[\!\(\*RowBox[{\"\\\"APIKey''\", \"\[Rule]\", StyleBox[\"string\",\"TI\"]}]\)] returns the response applying the specified \!\(\*StyleBox[\"string\",\"TI\"]\) to the chosen option. N.B. Option names are given as strings.
41+
The options to choose from:
42+
\"APIKey\": Your \!\(\*TemplateBox[{\"authentication key\", \"https://elevenlabs.io/docs/api-reference/authentication\"}, \"HyperlinkURL\"]\) to access ElevenLabs API; defaults to $XILabsAPIKey.
43+
\!\(\*TemplateBox[{\"Read on ElevenLabs API webpage\", \"https://elevenlabs.io/docs/api-reference/text-to-speech/convert\"}, \"HyperlinkURL\"]\)";
44+
45+
46+
(* Options *)
47+
48+
(* Constants *)
49+
$XILabsURL::usage = "URL for all queries to the ElevenLabs API.
50+
\!\(\*TemplateBox[{\"Read on ElevenLabs API webpage\", \"https://elevenlabs.io/docs/api-reference/authentication#making-requests\"}, \"HyperlinkURL\"]\)";
51+
$XILabsAPIKey::usage = "Key used for authentication during API requests to ElevenLabs.
52+
\!\(\*TemplateBox[{\"Read on ElevenLabs API webpage\", \"https://elevenlabs.io/docs/api-reference/authentication\"}, \"HyperlinkURL\"]\)";
53+
54+
55+
Begin["`Private`"] (* Begin Private Context *)
56+
57+
Clear[$XILabsURL,$XILabsAPIKey]
58+
(*
59+
$XILabsURL, $XILabsAPIKey and etc. are effectively set to themselves
60+
so that they can enter all the package functions. Then they can be changed during the session
61+
and take an effect on all the functions, where they are used.
62+
*)
63+
64+
65+
(* old name is TTSFromElevenLabs *)
66+
textToSpeechXI::connect = "A message was generated while connecting to `1`: `2`";
67+
textToSpeechXI::err = "Audio was not generated while connecting to `1`: `2`";
68+
Options[textToSpeechXI] = {
69+
"enable_logging" -> True,
70+
"output_format" -> "mp3_44100_128",
71+
"model_id" -> "eleven_multilingual_v1",
72+
"language_code" -> Null,
73+
"voice_settings" -> {
74+
"stability" -> 0.5,
75+
"similarity_boost" -> 0.8,
76+
"style" -> 0.0,
77+
"use_speaker_boost" -> True
78+
},
79+
"pronunciation_dictionary_locators" -> {},
80+
"seed" -> Null,
81+
"previous_text" -> Null,
82+
"next_text" -> Null,
83+
"previous_request_ids" -> {},
84+
"next_request_ids" -> {},
85+
"apply_text_normalization" -> "auto",
86+
87+
"Directory" -> $TemporaryDirectory,
88+
"FileName" -> "voice",
89+
"Format" -> "mp3",
90+
91+
"APIKey" -> $XILabsAPIKey
92+
};
93+
textToSpeechXI[voiceid_?StringQ, text_?StringQ, OptionsPattern[]] := Catch[Block[
94+
{
95+
apiurl, assoc, request, result, detail
96+
},
97+
98+
apiurl = StringJoin[$XILabsURL, "text-to-speech/" <> voiceid <> "/stream/"];
99+
assoc = Association[
100+
Method -> "POST",
101+
"ContentType" -> "application/json",
102+
"Body" -> ExportString[{
103+
"enable_logging" -> OptionValue["enable_logging"],
104+
"output_format" -> OptionValue["output_format"],
105+
"text" -> text,
106+
"model_id" -> OptionValue["model_id"],
107+
"language_code" -> OptionValue["language_code"],
108+
"voice_settings" -> OptionValue["voice_settings"],
109+
"pronunciation_dictionary_locators" -> OptionValue["pronunciation_dictionary_locators"],
110+
"seed" -> OptionValue["seed"],
111+
"previous_text" -> OptionValue["previous_text"],
112+
"next_text" -> OptionValue["next_text"],
113+
"previous_request_ids" -> OptionValue["previous_request_ids"],
114+
"next_request_ids" -> OptionValue["next_request_ids"],
115+
"apply_text_normalization" -> OptionValue["apply_text_normalization"]
116+
}, "JSON"],
117+
"Headers" -> {"xi-api-key" -> OptionValue["APIKey"]}
118+
];
119+
120+
request = Check[{"result" -> URLExecute[HTTPRequest[apiurl, assoc]]}, {"result" -> Null}];
121+
122+
result = Lookup[request, "result"];
123+
If[
124+
result === Null,
125+
Message[textToSpeechXI::connect, $XILabsURL, "Connection problem..."];
126+
Throw[$Failed],
127+
If[
128+
AudioQ[result],
129+
Export[FileNameJoin[{OptionValue["Directory"], OptionValue["FileName"] <> "." <> OptionValue["Format"]}], result];
130+
result,
131+
detail = StringJoin[Riffle[Flatten[Fold[Lookup, result, {"detail", {"status", "message"}}]], " "]];
132+
Message[textToSpeechXI::err, $XILabsURL, detail];
133+
Throw[$Failed]
134+
]
135+
](* end If *)
136+
](* end Block *)](* end Catch*);
137+
SyntaxInformation[textToSpeechXI] = {"ArgumentsPattern" -> {_,_,OptionsPattern[]}};
138+
139+
140+
VoicesXI::connect = "A message was generated while connecting to `1`: `2`";
141+
VoicesXI::err = "Request was not successful while connecting to `1`: `2`";
142+
Options[VoicesXI] = {"APIKey" -> $XILabsAPIKey};
143+
VoicesXI[OptionsPattern[]] := Catch[Block[
144+
{
145+
apiurl, assoc, request, result
146+
},
147+
apiurl = StringJoin[$XILabsURL, "voices"];
148+
assoc = <|
149+
Method -> "GET",
150+
"ContentType" -> "application/json",
151+
"Body" -> "",
152+
"Headers" -> {"xi-api-key" -> OptionValue["APIKey"]}
153+
|>;
154+
155+
request = Check[URLExecute[HTTPRequest[apiurl, assoc]], Null];
156+
157+
If[
158+
request === Null,
159+
Message[VoicesXI::connect, $XILabsURL, "Connection problem..."];
160+
Throw[$Failed],
161+
result = Lookup[request, "voices"];
162+
If[
163+
MissingQ[result],
164+
Message[VoicesXI::err, $XILabsURL, Lookup[request, "detail"]];
165+
Throw[$Failed],
166+
Fold[Lookup, result, {{"voice_id", "name"}}]
167+
]
168+
](* end If *)
169+
](* end Block *)](* end Catch *);
170+
SyntaxInformation[VoicesXI] = {"ArgumentsPattern" -> {OptionsPattern[]}};
171+
172+
173+
ModelsXI::connect = "A message was generated while connecting to `1`: `2`";
174+
ModelsXI::err = "Request was not successful while connecting to `1`: `2`";
175+
Options[ModelsXI] = {"APIKey" -> $XILabsAPIKey};
176+
ModelsXI[OptionsPattern[]] := Catch[Block[
177+
{
178+
apiurl, assoc, request, result
179+
},
180+
apiurl = StringJoin[$XILabsURL, "models"];
181+
assoc = <|
182+
Method -> "GET",
183+
"ContentType" -> "application/json",
184+
"Body" -> "",
185+
"Headers" -> {"xi-api-key" -> OptionValue["APIKey"]}
186+
|>;
187+
188+
request = Check[URLExecute[HTTPRequest[apiurl, assoc]], Null];
189+
190+
If[
191+
request === Null,
192+
Message[ModelsXI::connect, $XILabsURL, "Connection problem..."];
193+
Throw[$Failed],
194+
result = Lookup[request, "detail"];
195+
If[
196+
Or @@ (MissingQ /@ result),
197+
Prepend[Fold[Lookup, request, {{"model_id", "name", "can_do_text_to_speech", "languages"}}],
198+
{"model_id", "name", "can_do_text_to_speech", "languages"}],
199+
Message[ModelsXI::err, $XILabsURL, result];
200+
Throw[$Failed]
201+
]
202+
](* end If *)
203+
204+
](* end Block *)](* end Catch *);
205+
SyntaxInformation[ModelsXI] = {"ArgumentsPattern" -> {OptionsPattern[]}};
206+
207+
208+
(* access to ElevenLabs api functions *)
209+
$XILabsURL = "https://api.elevenlabs.io/v1/";
210+
(* after the package constants have entered all the functions they can be set to empy strings that will be
211+
their initial values *)
212+
$XILabsAPIKey = "";
213+
214+
215+
End[] (* End Private Context *)
216+
217+
218+
(Attributes[#] = {Protected, ReadProtected}) & /@ Complement[Names[Evaluate[$Context<>"*"]], {"$XILabsURL","$XILabsAPIKey"}]
219+
220+
221+
EndPackage[]

0 commit comments

Comments
 (0)