Good afternoon!
My telegram bot is written in Python and is very simple. It includes thousands of lines of functions of the same type (example below) and ends with a line bot.infinity_polling(True)
#bot.message_handler(commands=['start'])
def com_start(m):
keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
keyboard.add(*[types.KeyboardButton(name) for name in ['🇷🇺Русский']])
keyboard.add(*[types.KeyboardButton(name) for name in ['🇬🇧English']])
keyboard.add(*[types.KeyboardButton(name) for name in ['🇩🇪German']])
keyboard.add(*[types.KeyboardButton(name) for name in ['🇹🇷Turkish']])
msg = bot.send_message(m.chat.id, '👋🏼Привет!',
reply_markup=keyboard)
bot.register_next_step_handler(msg, starter)
def starter(m):
if m.text == '🇷🇺Русский':
second(m)
elif m.text == '🇬🇧English':
secondeng(m)
elif m.text == '🇩🇪German':
secondgerm(m)
elif m.text == '🇹🇷Turkish':
secondtur(m)
else:
msg = bot.send_message(m.chat.id, 'Используйте кнопки меню для общения с ботом OTON ⤵️')
com_start(m)
My bot works with gitlab, after each change in the code I commit, push it and Run Pipeline via CI/CD.
The problem is that the GetUpdates method (https://api.telegram.org/bot.../getUpdates) while the bot is running gives {"ok":true,"result":[]} and nothing more. But when I stop the bot and refresh the page - it gives me all that I need:
{"ok":true,"result":[{"update_id":57670007,
"message":{"message_id":10586,"from":{"id":435418164,"is_bot":false,"first_name":"Nika","last_name":"Fenina","username":"yanikailinet","language_code":"ru"},"chat":{"id":435418164,"first_name":"Nika","last_name":"Fenina","username":"yanikailinet","type":"private"},"date":1590065990,"text":"hello"}}
Can I solve this problem somehow? I need to get the information I need while the bot is running.
PS: no webhooks connected
You cannot make simultaneous getUpdates requests. It shows this error.
Conflict: terminated by other getUpdates request; make sure that only one bot instance is running
You can save the information of ["result"] inside the code only in some file.
Related
While making a discord bot in Python using discord-ui and discord.py, I wanted to make a command which does specific stuff for specific roles. Like if I have the att_role and aot_role, it would execute the code for both of these roles, and if I add another role like est_role, it would execute its code too. I am using PyCharm as the IDE here.
I am a novice programmer, so I don't know if this is the best way to do this, but when I do it I get the error of 'The application did not respond'. Here is when it works and when not:
When I have the att_role, it works perfectly even if I add more roles from the list. If I remove the att_role and add two other roles from the list, it would work for those too. If I have the rs_role only, it would work for it too. However, if I have only the aot_role or only the est_role, I get this error after running:- The application did not respond in the discord channel. If I add any other role with these, it would work perfectly. It doesn't show any error in my IDE(PyCharm).
If you don't understand correctly what I mean, just tell me the best way for doing this: Making different stuff for different roles.
Here is my code:
import discord
from discord.ext import commands
from discord_ui import UI, SelectOption, SelectMenu
import asyncio
# Clients
client = commands.Bot(' ')
client.remove_command('help')
ui = UI(client)
#ui.slash.command()
async def log(ctx):
"""Use this command to log trainings/tryouts"""
# These are the roles allowed to use this command
allowed_roles = [
'Advanced Trooper Training Section',
'Advanced Officer Training Section,',
'Recruiting Staff',
'Academy Instructor'
'Executive Sergeant Training Section',
'TB Bot Manager'
]
author_roles = ctx.author.roles
# If statement to check if the user can use this command
if any(role.name in allowed_roles for role in author_roles):
att_role = discord.utils.get(author_roles, name='Advanced Trooper Training Section')
aot_role = discord.utils.get(author_roles, name='Advanced Officer Training Section')
rs_role = discord.utils.get(author_roles, name='Recruiting Staff')
ai_role = discord.utils.get(author_roles, name='Academy Instructor')
est_role = discord.utils.get(author_roles, name='Executive Sergeant Training Section')
manager_role = discord.utils.get(author_roles, name='TB Bot Manager')
# Different stuff for different roles
if att_role is not None and att_role.name == 'Advanced Trooper Training Section':
await ctx.send('att') # Sample Stuff
if rs_role is not None and rs_role.name == 'Recruiting Staff':
await ctx.send('rs') # Sample Stuff
if ai_role is not None and ai_role.name == 'Academy Instructor':
await ctx.send('ai') # Sample Stuff
if est_role is not None and est_role.name == 'Executive Sergeant Training Section':
await ctx.send('est') # Sample Stuff
if manager_role is not None and manager_role.name == 'TB Bot Manager':
await ctx.send('manager') # Sample Stuff
if aot_role is not None and aot_role.name == 'Advanced Officer Training Section':
await ctx.send('aot') # Sample Stuff
client.run(TOKEN)
If your bot does not respond to an interaction within 3 seconds, the interaction will fail (although not necessarily an error has occured in your application). You can defer if you know it will take longer time.
In Pycord, it is located under InteractionResponse.defer but since you didn't mention which library you're using, I don't know which method you have to call.
You should use
await ctx.respond()
instead of
await ctx.send()
when dealing with slash commands. If this doesn't work, it'll be due to an error in the code (It should appear in terminal)
A previous answer on here suggests using ctx.respond() instead of ctx.send(), this solution will throw an error in the current version of discord.py:
Instead use:
await ctx.reply()
if message.content.startswith("*run"):
ticker = message.content[5:]
try:
df = exchange.fetch_ohlcv(ticker)
await message.channel.send('Read Command: will send message if long or short opportunity arises!')
valid = True
except:
await message.channel.send('Invalid ticker')
if valid == True:
bars = exchange.fetch_ohlcv(ticker, timeframe='5m', limit=210)
df = pd.DataFrame(bars, columns=['time','high', 'low', 'open','close', 'volume'])
close = df.iloc[-1]['close']
while valid == True:
if message.content == "*stop":
valid = False
trade = strat1(ticker)
The code above is for a discord bot that a friend and I are working on for a side project. My problem is in the last few lines of the code,
while valid == True:
if message.content == "*stop":
valid = False:
When a user types in *run (ticker) in discord, the code searches through data to see whether that ticker is valid or not and then based on the response, a loop will run. During that loop, I want the user to have the option to stop it without having to turn off the bot completely, but I can't seem to get it to register the *stop command. Every time I run it, it just moves past that command completely. So, if anyone knows how to fix this, please let me know.
Thank you for reading.
What you're trying to do is to interrupt a running execution. To do it in Python, you will need to use a multiprocessing algorithm.
You can try to use the multiprocessing module,
Firstly, design a master thread that listens for command in the discord server, which you already did.
Then you would wanna put the actual service, that needs to be run after the command, in a function
def thread_worker():
bars = exchange.fetch_ohlcv(ticker, timeframe='5m', limit=210)
df = pd.DataFrame(bars, columns=['time','high', 'low', 'open','close', 'volume'])
close = df.iloc[-1]['close']
trade = strat1(ticker)
Then when a command to start is received, you can initiate a new process and run the corresponding job
newProcess = multiprocessing.Process(target=thread_worker)
newProcess.start()
When your master thread receives the kill signal
newProcess.terminate()
I'm trying to get my Python Slack bot to automatically reply in a thread if I post it commands in one. However, regardless of where I post my commands - in a thread or otherwise, it still replies as a general message.
I wish to get it to reply in a thread. Here's my code so far (I've truncated most of the initializing and startup code for the sake of brevity):
import os, time, re, inspect, functools
from slackclient import SlackClient
class Bot(object):
def __init__(self, token):
...
def startup(self):
...
def parse_bot_commands(self, slack_events):
"""
Parses a list of events coming from the Slack RTM API to find bot commands.
If a bot command is found, this function returns a tuple of command and channel.
If its not found, then this function returns None, None.
"""
for event in slack_events:
if event["type"] == "message" and not "subtype" in event:
user_id, message = self.parse_direct_mention(event["text"])
if user_id == self.starterbot_id:
return message, event["channel"]
return None, None
def parse_direct_mention(self, message_text):
"""
Finds a direct mention (a mention that is at the beginning) in message text
and returns the user ID which was mentioned. If there is no direct mention, returns None
"""
matches = re.search(self.MENTION_REGEX, message_text)
# the first group contains the username, the second group contains the remaining message
return (matches.group(1), matches.group(2).strip()) if matches else (None, None)
def handle_command(self, command, channel):
"""
Executes bot command if the command is known
"""
# Default response is help text for the user
default_response = "Not sure what you mean. Try *{}*.".format(self.EXAMPLE_COMMAND)
# Finds and executes the given command, filling in response
response = None
# NOTE: This is where you start to implement more commands!
if command.lower().startswith("roll"):
response = 'Rock and Roll!"
# Sends the response back to the channel
self.slack_client.api_call("chat.postMessage", channel=channel, text=response or default_response)
'''START THE BOT!'''
#Initialize the token (when installing the app)
bot = Bot('xxx-xxx')
bot.startup()
Slash commands do not work properly in threads. Its a known issue which has so far not been fixed.
See also this answer: Can a Slack bot get the thread id that a slash command was sent from?
I am building some telegram bot on python (using this framework pyTelegramBotAPI). And I ran into the problem with user input. I need save user input(it can be any text) after certain bot's message. For example:
Bot: - Please describe your problem.
User: - Our computer doesn't work.
Then I need to save this text "Our computer doesn't work" to some variable and go to the next step.
Here's my code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def handle_start(message):
keyboard = types.InlineKeyboardMarkup()
callback_button = types.InlineKeyboardButton(text="Help me!", callback_data="start")
keyboard.add(callback_button)
bot.send_message(message.chat.id, "Welcome I am helper bot!", reply_markup=keyboard)
#bot.inline_handler(lambda query: len(query.query) > 0)
def query_text(query):
kb = types.InlineKeyboardMarkup()
kb.add(types.InlineKeyboardButton(text="Help me!", callback_data="start"))
results = []
single_msg = types.InlineQueryResultArticle(
id="1", title="Press me",
input_message_content=types.InputTextMessageContent(message_text="Welcome I am helper bot!"),
reply_markup=kb
)
results.append(single_msg)
bot.answer_inline_query(query.id, results)
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
if call.message:
if call.data == "start":
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Please describe your problem.")
#here I need wait for user text response, save it and go to the next step
I have the idea with using message_id in statement, but still can't implement it. How I can solve this? Any ideas? Thank you.
This will help you
https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def start(message):
sent = bot.send_message(message.chat.id, 'Please describe your problem.')
bot.register_next_step_handler(sent, hello)
def hello(message):
open('problem.txt', 'w').write(message.chat.id + ' | ' + message.text + '||')
bot.send_message(message.chat.id, 'Thank you!')
bot.send_message(ADMIN_ID, message.chat.id + ' | ' + message.text)
bot.polling()
its not a python or even programming related question. its more like designing problem. but anyway.
the solution is keeping session for users. for example user send you:
Our computer doesn't work.
at first you create a session for this user(the identity should be a user id) then send him/her a proper message. when user send the next message at first you look at the user status and see if he/she has a session or not. if he/she has session you continue with second step. i develop a bot like this and used dictionary in order to store users sessions. but it make all thing little complicated.
You can use Forcereply.
Upon receiving a message with this object, Telegram clients will display a reply interface to the user (act as if the user has selected the bot‘s message and tapped ’Reply'). This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode. https://core.telegram.org/bots/api#forcereply
i know how fix that. It took 3 years for solution.
Just look at my code and make your own. Thx
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call): #your call
UserID = str(call.message.chat.id)
if call.data == 'PhotoTEXT':
#bot.message_handler(content_types=['text'])
def SetTEXTonPHOTO(message): # THIS FUNCTION
sent = bot.send_message(message.chat.id,'send me text')
bot.register_next_step_handler(sent, TextONphoto)
def TextONphoto(message): #Thsi function add text on photo
im = Image.open('UserData/Files/photos/not_converted/'+UserID+'.jpg')
idraw = ImageDraw.Draw(im)
text = message.text
font = ImageFont.truetype("arial.ttf", size=18)
idraw.text((10, 10), text, font=font)
im.save('UserData/Files/photos/converted/'+UserID+'.jpg')
im.show()
SetTEXTonPHOTO(call.message) #just run your function
with open('UserData/Files/photos/converted/'+UserID+'.jpg', 'rb') as file:
bot.send_document(UserID,file)
I think i helped you friends <3
You should save the data in cache or database.
I want to use SleekXMPP and automatically accept all chat room invites that are sent to me. I know that the xep_0045 plugin can detect when I receive an invite, as I am notified in the debugger. I am still pretty new to Python and any help would be appreciated.
So far, I've found a function called handle_groupchat_invite in the xep_0045 plugin. Specifically, this code:
def plugin_init(self):
#...
self.xmpp.registerHandler(Callback('MUCInvite', MatchXMLMask("<message xmlns='%s'><x xmlns='http://jabber.org/protocol/muc#user'><invite></invite></x></message>" % self.xmpp.default_ns), self.handle_groupchat_invite))
#...
def handle_groupchat_invite(self, inv):
""" Handle an invite into a muc.
"""
logging.debug("MUC invite to %s from %s: %s", inv['from'], inv["from"], inv)
if inv['from'].bare not in self.rooms.keys():
self.xmpp.event("groupchat_invite", inv)
So I see this method at work as I see the "MUC invite to..." message in the Terminal log. From there, I would expect that I need to use self.plugin['xep_0045'].joinMUC() to join the chat room's URL (given by inv["from"]). However, I am not exactly sure where I should call this code in my script.
Thanks again for the help.
Update: I've also tried using add_event_handler in the __init__ function. Specifically my code is:
def __init__(self, jid, password, room, nick):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.room = room
self.nick = nick
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
# The groupchat_message event is triggered whenever a message
# stanza is received from any chat room. If you also also
# register a handler for the 'message' event, MUC messages
# will be processed by both handlers.
self.add_event_handler("groupchat_message", self.muc_message)
# The groupchat_presence event is triggered whenever a
# presence stanza is received from any chat room, including
# any presences you send yourself. To limit event handling
# to a single room, use the events muc::room#server::presence,
# muc::room#server::got_online, or muc::room#server::got_offline.
self.add_event_handler("muc::%s::got_online" % self.room,
self.muc_online)
self.add_event_hander("groupchat_invite", self.sent_invite)
From there, I created the sent_invite function, code is here:
def sent_invite(self, inv):
self.plugin['xep_0045'].joinMUC(inv["from"], self.nick, wait=True)
However, I get the following error when I do this:
File "muc.py", line 66, in init
self.add_event_hander("groupchat_invite", self.sent_invite) AttributeError: 'MUCBot' object has no attribute 'add_event_hander'
Yet in the xep_0045 plugin I see this code: self.xmpp.event("groupchat_invite", inv). According to the Event Handlers SleekXMPP wiki page,
Stream events arise whenever particular stanzas are received from the XML stream. Triggered events are created whenever xmpp.event(name, data) is called (where xmpp is a SleekXMPP object).
Can someone please explain why I am getting the error? I've also tried using
self.add_event_hander("muc::groupchat_invite", self.sent_invite)
but also without success.
I just downloaded SleekXMPP from git and add groupchat_invite handler like this and it works:
diff --git a/examples/muc.py b/examples/muc.py
index 5b5c764..e327fac 100755
--- a/examples/muc.py
+++ b/examples/muc.py
## -61,7 +61,10 ## class MUCBot(sleekxmpp.ClientXMPP):
# muc::room#server::got_online, or muc::room#server::got_offline.
self.add_event_handler("muc::%s::got_online" % self.room,
self.muc_online)
-
+ self.add_event_handler("groupchat_invite", self.accept_invite)
+
+ def accept_invite(self, inv):
+ print("Invite from %s to %s" %(inv["from"], inv["to"]))
def start(self, event):
"""