Im trying to create a slack bot with slack_bolt package that is searching if there are matches in slack history in the channel on a new message. For some reason app.message is triggered on messages that have been sent before the app was running. Is this preventable or do i have to handle this case? It would be to best to prevent it since if i want to use this on a channel with a big history that might cause some problems. I don't want it to check all the X thousand messages in the history.
wanted result:
ME: Hi!
-- starting slack app --
ME: Hi!
SlackBOT in thread: A similar message has been posted: (link to first massage)
result:
ME: Hi!
SlackBOT in thread: A similar message has been posted (link to itself) (this only arrives after the slackbot message to the second Hi)
-- starting slack app --
ME: Hi!
SlackBOT in thread: A similar message has been posted (with link to first message)
import os
import json
import ssl
import certifi
from slack_bolt import App
from slack_sdk.web import WebClient
from slack_bolt.adapter.socket_mode import SocketModeHandler
from utils import get_list_of_same_message_indexes, get_ts_of_message_for_link
history_limit = 50
ssl_context = ssl.create_default_context(cafile=certifi.where())
slack_client = WebClient(token=os.environ['BOT_TOKEN'], ssl=ssl_context)
app = App(client=slack_client)
#app.message(".*")
def check_history(message, say):
# say() sends a message to the channel where the event was triggered
history = app.client.conversations_history(channel=slack_channel_ID,limit=history_limit).get("messages")
#if the message is not comming from a thread
print(message.get("text"))
if not message.get("thread_ts"):
print("new message")
thread= message.get("ts")
list_of_same_messages = get_list_of_same_message_indexes(message,history)
if len(list_of_same_messages) > 0:
print(list_of_same_messages)
example_ts = get_ts_of_message_for_link(history[list_of_same_messages[0]])
print(example_ts)
#channel = history[list_of_same_messages[0]].get("channel")
message_text = f"A similar message has been posted: https://test-dev.slack.com/archives/{slack_channel_ID}/p{example_ts}"
say({"text": message_text,"thread_ts": thread})
else:
print("Nothing")
if __name__ == "__main__":
SocketModeHandler(app, os.environ["APP_TOKEN"]).start()
Related
I'm a noobie at Python and was just messing around, but now I'm really curious why it isn't working. I'm currently trying to build a telegram bot that generates an image based on the text given to the bot. I think there might be a problem with my DeepAI api? When I click this link: https://api.deepai.org/api/text2img i always get the error
{"err": "error processing given inputs from request"}
. The bot is linked but gives me the error as in the code below. My code below:
import requests
import json
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
def text_to_image(update, context):
# Get the text from the user
text = update.message.text
# Set up the DeepAI API request
api_key = "{{ api }}"
headers = {
"api-key": api_key
}
data = {
"text": text
}
# Make the request to the DeepAI API
response = requests.post("https://api.deepai.org/api/text2img", headers=headers, json=data)
if response.status_code != 200:
update.message.reply_text("An error occurred while generating the image. Please try again later.")
return
# Get the generated image from the response
response_json = response.json()
image_url = response_json["output_url"]
# Send the generated image to the user
context.bot.send_photo(chat_id=update.effective_chat.id, photo=image_url)
def main():
# Set up the Telegram bot
updater = Updater(token="{{ api }}", use_context=True)
dispatcher = updater.dispatcher
# Add the text_to_image handler
text_to_image_handler = MessageHandler(Filters.text, text_to_image)
dispatcher.add_handler(text_to_image_handler)
# Start the bot
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
I've tried changing code and different things but nothing seems to work, i'm really stuck right now
From the looks of it, it's an error on the API side of things. The status code of the API server depends on traffic and account/key.
Things to do:
Check if your API key is valid and wait when server works on google, then try to run your code
Hi i want to send message from bot in specific time (without message from me), for example every Saturday morning at 8:00am.
Here is my code:
import telebot
import config
from datetime import time, date, datetime
bot = telebot.TeleBot(config.bot_token)
chat_id=config.my_id
#bot.message_handler(commands=['start', 'help'])
def print_hi(message):
bot.send_message(message.chat.id, 'Hi!')
#bot.message_handler(func=lambda message: False) #cause there is no message
def saturday_message():
now = datetime.now()
if (now.date().weekday() == 5) and (now.time() == time(8,0)):
bot.send_message(chat_id, 'Wake up!')
bot.polling(none_stop=True)
But ofc that's not working.
Tried with
urlopen("https://api.telegram.org/bot" +bot_id+ "/sendMessage?chat_id=" +chat_id+ "&text="+msg)
but again no result. Have no idea what to do, help please with advice.
I had this same issue and I was able to solve it using the schedule library. I always find examples are the easiest way:
import schedule
import telebot
from threading import Thread
from time import sleep
TOKEN = "Some Token"
bot = telebot.TeleBot(TOKEN)
some_id = 12345 # This is our chat id.
def schedule_checker():
while True:
schedule.run_pending()
sleep(1)
def function_to_run():
return bot.send_message(some_id, "This is a message to send.")
if __name__ == "__main__":
# Create the job in schedule.
schedule.every().saturday.at("07:00").do(function_to_run)
# Spin up a thread to run the schedule check so it doesn't block your bot.
# This will take the function schedule_checker which will check every second
# to see if the scheduled job needs to be ran.
Thread(target=schedule_checker).start()
# And then of course, start your server.
server.run(host="0.0.0.0", port=int(os.environ.get('PORT', 5000)))
I hope you find this useful, solved the problem for me :).
You could manage the task with cron/at or similar.
Make a script, maybe called alarm_telegram.py.
#!/usr/bin/env python
import telebot
import config
bot = telebot.TeleBot(config.bot_token)
chat_id=config.my_id
bot.send_message(chat_id, 'Wake up!')
Then program in cron like this.
00 8 * * 6 /path/to/your/script/alarm_telegram.py
Happy Coding!!!
If you want your bot to both schedule a message and also get commands from typing something inside, you need to put Thread in a specific position (took me a while to understand how I can make both polling and threading to work at the same time).
By the way, I am using another library here, but it would also work nicely with schedule library.
import telebot
from apscheduler.schedulers.blocking import BlockingScheduler
from threading import Thread
def run_scheduled_task():
print("I am running")
bot.send_message(some_id, "This is a message to send.")
scheduler = BlockingScheduler(timezone="Europe/Berlin") # You need to add a timezone, otherwise it will give you a warning
scheduler.add_job(run_scheduled_task, "cron", hour=22) # Runs every day at 22:00
def schedule_checker():
while True:
scheduler.start()
#bot.message_handler(commands=['start', 'help'])
def print_hi(message):
bot.send_message(message.chat.id, 'Hi!')
Thread(target=schedule_checker).start() # Notice that you refer to schedule_checker function which starts the job
bot.polling() # Also notice that you need to include polling to allow your bot to get commands from you. But it should happen AFTER threading!
hi and thanks for your answer. i want to create a bot for forward message to my channel and delete the last message every 1 minute
i made that but i have some problem for removing the last message. i cant get the last message id from my channel to the bot.
my source is:
from telegram.bot import Bot
from telegram.update import Update
from telegram.ext.updater import Updater
from telegram.ext.callbackcontext import CallbackContext
from telegram.ext.messagehandler import MessageHandler
from telegram.ext.filters import Filters
from telegram.chataction import ChatAction
from time import sleep
import telegram_send
import socket
import telegram
import json
api_key="My API Key"
user_id = "My User Id"
updater = Updater(api_key, use_context=True)
bot = telegram.Bot(token=api_key)
def echo(update: Update, context: CallbackContext):
context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING)
sleep(60)
if update.message['photo'] == []:
bot.send_message(chat_id=user_id, text=update.message.text)
else:
fileID = update.message['photo'][-1]['file_id']
context.bot.sendPhoto(chat_id = user_id,caption=update.message['caption'],photo = fileID)
msg_id = update.message._id_attrs[]
#------------- And Also i user that too -------------
#msg_id=update.message.message_id
#------------- -------------
context.bot.delete_message(chat_id=user_id, message_id=msg_id)
update.effective_chat
update.effective_user
update.effective_message
print(json.dumps(update.to_dict(), indent=2))
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.document | Filters.photo, echo))
dp.add_handler(MessageHandler(Filters.text, echo))
updater.start_polling()
and when i use that code this error will show:
The message_id that you want to remove is not exist....
actually i type a message id in manually for delete message and it was work
but i want to delete that message auto
please help me to do that. thanks
I fixed That With Python-Telegram-Bot Version 20
Read This Docs:
https://docs.python-telegram-bot.org/en/v20.0a2/
I'm curious about how you are supposed to express that you want a message delivered to a Kafka topic in faust. The example in their readme doesn't seem to write to a topic:
import faust
class Greeting(faust.Record):
from_name: str
to_name: str
app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)
#app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
print(f'Hello from {greeting.from_name} to {greeting.to_name}')
#app.timer(interval=1.0)
async def example_sender(app):
await hello.send(
value=Greeting(from_name='Faust', to_name='you'),
)
if __name__ == '__main__':
app.main()
I would expect hello.send in the above code to publish a message to the topic, but it doesn't appear to.
There are many examples of reading from topics, and many examples of using the cli to push an ad-hoc message. After combing through the docs, I don't see any clear examples of publishing to topics in code. Am I just being crazy and the above code should work?
You can use sink to tell Faust where to deliver the results of an agent function. You can also use multiple topics as sinks at once if you want.
#app.agent(topic_to_read_from, sink=[destination_topic])
async def fetch(records):
async for record in records:
result = do_something(record)
yield result
The send() function is the correct one to call to write to topics. You can even specify a particular partition, just like the equivalent Java API call.
Here is the reference for the send() method:
https://faust.readthedocs.io/en/latest/reference/faust.topics.html#faust.topics.Topic.send
If you want a Faust producer only (not combined with a consumer/sink), the original question actually has the right bit of code, here's a fully functional script that publishes messages to a 'faust_test' Kafka topic that is consumable by any Kafka/Faust consumer.
Run the code below like this: python faust_producer.py worker
"""Simple Faust Producer"""
import faust
if __name__ == '__main__':
"""Simple Faust Producer"""
# Create the Faust App
app = faust.App('faust_test_app', broker='localhost:9092')
topic = app.topic('faust_test')
# Send messages
#app.timer(interval=1.0)
async def send_message(message):
await topic.send(value='my message')
# Start the Faust App
app.main()
So we just ran into the need to send a message to a topic other than the sink topics.
The easiest way we found was: foo = await my_topic.send_soon(value="wtfm8").
You can also use send directly like below using the asyncio event loop.
loop = asyncio.get_event_loop()
foo = await ttopic.send(value="wtfm8??")
loop.run_until_complete(foo)
Dont know how relevant this is anymore but I came across this issue when trying to learn Faust. From what I read, here is what is happening:
topic = app.topic('hello-topic', value_type=Greeting)
The misconception here is that the topic you have created is the topic you are trying to consume/read from. The topic you created currently does not do anything.
await hello.send(
value=Greeting(from_name='Faust', to_name='you'),
)
this essentially creates an intermediate kstream which sends the values to your hello(greetings) function. def hello(...) will be called when there is a new message to the stream and will process the message that is being sent.
#app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
print(f'Hello from {greeting.from_name} to {greeting.to_name}')
This is receiving the kafka stream from hello.send(...) and simply printing it to the console (no output to the 'topic' created). This is where you can send a message to a new topic. so instead of printing you can do:
topic.send(value = "my message!")
Alternatively:
Here is what you are doing:
example_sender() sends a message to hello(...) (through intermediate kstream)
hello(...) picks up the message and prints it
NOTICE: no sending of messages to the correct topic
Here is what you can do:
example_sender() sends a message to hello(...) (through intermediate kstream)
hello(...) picks up the message and prints
hello(...) ALSO sends a new message to the topic created(assuming you are trying to transform the original data)
app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)
output_topic = app.topic('test_output_faust', value_type=str)
#app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
new_message = f'Hello from {greeting.from_name} to {greeting.to_name}'
print(new_message)
await output_topic.send(value=new_message)
I found a solution to how to send data to kafka topics using Faust, but I don't really understand how it works.
There are several methods for this in Faust: send(), cast(), ask_nowait(), ask(). In the documentation they are called RPC operations.
After creating the sending task, you need to run the Faust application in the mode Client-Only Mode. (start_client(), maybe_start_client())
The following code (the produce() function) demonstrates their application (pay attention to the comments):
import asyncio
import faust
class Greeting(faust.Record):
from_name: str
to_name: str
app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)
result_topic = app.topic('result-topic', value_type=str)
#app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
s = f'Hello from {greeting.from_name} to {greeting.to_name}'
print(s)
yield s
async def produce(to_name):
# send - universal method for sending data to a topic
await hello.send(value=Greeting(from_name='SEND', to_name=to_name), force=True)
await app.maybe_start_client()
print('SEND')
# cast - allows you to send data without waiting for a response from the agent
await hello.cast(value=Greeting(from_name='CAST', to_name=to_name))
await app.maybe_start_client()
print('CAST')
# ask_nowait - it seems to be similar to cast
p = await hello.ask_nowait(
value=Greeting(from_name='ASK_NOWAIT', to_name=to_name),
force=True,
reply_to=result_topic
)
# without this line, ask_nowait will not work; taken from the ask implementation
await app._reply_consumer.add(p.correlation_id, p)
await app.maybe_start_client()
print(f'ASK_NOWAIT: {p.correlation_id}')
# blocks the execution flow
# p = await hello.ask(value=Greeting(from_name='ASK', to_name=to_name), reply_to=result_topic)
# print(f'ASK: {p.correlation_id}')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(produce('Faust'))
Starting Fast worker with the command faust -A <example> worker
Then we can launch the client part of the application and check that everything is working: python <example.py>
<example.py> output:
SEND
CAST
ASK_NOWAIT: bbbe6795-5a99-40e5-a7ad-a9af544efd55
It is worth noting that you will also see a traceback of some error that occurred after delivery, which does not interfere with the program (it seems so)
Faust worker output:
[2022-07-19 12:06:27,959] [1140] [WARNING] Hello from SEND to Faust
[2022-07-19 12:06:27,960] [1140] [WARNING] Hello from CAST to Faust
[2022-07-19 12:06:27,962] [1140] [WARNING] Hello from ASK_NOWAIT to Faust
I don't understand why it works this way, why it's so difficult and why very little is written about in the documentation 😓.
I am trying to use my bot to delete certain messages in a slack channel with this api call
import os
import time
import re
from slackclient import SlackClient
slack_client = SlackClient(
'xsssssseeeeeeee')
slack_mute_bot_id = None
def delete_message(slack_event):
for event in slack_event:
if event["type"] == "message":
message_text = event['text']
time_stamp = event['ts']
channel_id = event['channel']
slack_client.api_call(
'chat.delete',
channel=channel_id,
ts=time_stamp,
as_user=True
)
print(message_text + " delted")
if __name__ == "__main__":
if slack_client.rtm_connect(with_team_state=False):
slack_mute_bot_id = slack_client.api_call("auth.test")["user_id"]
while True:
# print(slack_client.rtm_read())
delete_message(slack_client.rtm_read())
time.sleep(1)
else:
print("Connection failed. Exception traceback printed above.")
I do not get any error message after doing this and the bot does not delete the message. I am using the bot user token. I have benn able to send message succesfully but the delete method does not work and still gives np responses
Refer - https://api.slack.com/methods/chat.delete
When used with a user token, this method may only delete messages
that user themselves can delete in Slack.
When used with a bot token, this method may delete only messages
posted by that bot.
I got stumbled into the same thing.