I am trying to build a slackbot for my group , I tried sample codes and some other things but its not sending message to the group.
first i tried via terminal
export SLACK_API_TOKEN="my_token_id"
Then
from slackclient import SlackClient
import os
slack_token = os.environ["SLACK_API_TOKEN"]
sc = SlackClient(slack_token)
sc.api_call(
"chat.postMessage",
channel="#random",
text="Hello from Python! :tada:",
thread_ts="283.5127(dummy_id)",
reply_broadcast=False
)
print(sc)
#<slackclient.client.SlackClient object at 0x109b77ba8>
But there is no message in slack group.
I tried with this code:
from slackclient import SlackClient
import os
slack_token = os.environ['SLACK_API_TOKEN']
sc = SlackClient(slack_token)
print(sc.api_call("channels.list"))
its retuning :
{'error': 'invalid_auth', 'ok': False}
I am not getting what i am doing wrong , Access token is correct , i want to post some messages via a bot , so how i can create a bot on slack and using that bot i can send messages via python ?
I had similar issues when I implemented a slack bot with php & symfony.
It's not that simple to create and configure the slack app, bot and OAuth permissions properly.
I explained all these configurations in this blog post if you need it: https://blog.eleven-labs.com/en/en/replace-erp-by-slack-bot-with-dialogflow-and-symfony/
Also my code in PHP is very similar to what you need to parse Slack requests and post to its API.
Summary, TL;DR:
Go to https://api.slack.com/apps and click on 'Create New App'.
In this app configuration, go to the left menu 'Bot Users' or from 'Basic Information' > 'Add features and functionality' > 'Bots'.
Still in this app config, go to the menu 'OAuth & Permissions' and allow the scope 'chat:write:bot' and copy the value of 'OAuth Access Token'
From your code, call 'chat.postMessage' API method with an 'Authorization' header using previous token value.
built this from some examples found on the web: liza daly - brobot : github.com
and
How to Build Your First Slack Bot with Python : fullstackpython.com
certainly not the best implementation but it functions as an appropriate answer to (i think)
import random
import time
import re
from slackclient import SlackClient
bot_id = None
slack_token = 'xoxb-no.more.mister.nice.gui'
sc = SlackClient(slack_token)
# constants
RTM_READ_DELAY = 1 # 1 second delay between reading from RTM
DEFAULT_RESPONSE = "greetings: 'hello', 'hi', 'greetings', 'sup', 'what's up' / commands: 'do'"
DEFAULT_COMMAND = "do"
MENTION_REGEX = "^<#(|[WU].+?)>(.*)"
def parse_bot_commands(slack_events):
"""
parses a list of events coming from the slack rtm api to find bot commands
:param slack_events:
:return:
"""
for event in slack_events:
if event["type"] == "message" and not "subtype" in event:
user_id, message = parse_direct_mention(event["text"])
if user_id == bot_id:
return message, event["channel"]
return None, None
def parse_direct_mention(message_text):
"""
finds direct message and returns user id
:param message_text:
:return:
"""
matches = re.search(MENTION_REGEX, message_text)
# the first group contains the user name, the second group contains
# the remaining message
return (matches.group(1), matches.group(2).strip()) if matches else (None, None)
def handle_command(command, channel):
"""
executes bot command if the command is known
:param command:
:param channel:
:return:
"""
GREETING_KEYWORDS = ("hello", "hi", "greetings", "sup", "what's up",)
GREETING_RESPONSES = ["'sup brah", "hey", "*headnod*", "didjageddathingahsencha?"]
# default response is help text for the user
default_response = "Not sure what you mean. Try *{}*.".format(DEFAULT_RESPONSE)
# finds and executes the given command, filling the response
response = None
#implement more commands below this line
if command in GREETING_KEYWORDS:
response = random.choice(GREETING_RESPONSES)
else:
if command.startswith(DEFAULT_COMMAND):
response = "Sure...write some more code and I'll do that"
# Sends the response back to the channel
sc.api_call(
"chat.postMessage",
channel="#the_danger_room",
as_user="true:",
text=response or default_response)
if __name__ == "__main__":
if sc.rtm_connect(with_team_state=False):
print("Connected and running!")
#call web api method auth.test to get bot usre id
bot_id = sc.api_call("auth.test")["user_id"]
while True:
command, channel = parse_bot_commands(sc.rtm_read())
if command:
handle_command(command, channel)
time.sleep(RTM_READ_DELAY)
else:
print("Connection failed. Exception traceback printed above.")
Related
The issue is that the third function never seems to respond.
I haven't been able to find a reason why this happens in the telegram documentation.
Please let me know if you have this issue or seen it and know the solution.
Even a post that references an issue like this would work.
Thank you so much for the assistance.
from email import message
import os
import re
import html
import json
import telebot
import requests
import http.client
from pytube import *
from dotenv import load_dotenv
load_dotenv()
# Creating hiding, and using API Keys
API_KEY = os.getenv("API_KEY")
RAPID_KEY = os.getenv("RAPID_API")
bot = telebot.TeleBot(API_KEY)
#bot.message_handler(commands="start")
# Creating a help message for guidance on how to use bot.
def help(message):
# Trying to send help message, if unable to send, throw an error message for the user.
try:
bot.send_message(message.chat.id, "Use \"Youtube\" and the video name to search for a video.\n")
except:
bot.send_message(message.chat.id, "There was an error fetching help, the bot may be offline.\n")
# Checking data and seeing if the word "YouTube" was used in order to start the search
def data_validation(message):
query = message.text.split()
if("youtube" not in query[0].lower()): # Set flag false if regular text
return False
else:
return True
#bot.message_handler(func=data_validation)
# Searching for youtube videos
# using RAPID API
def search(message):
query = message.text.split()
# Check if data is valid, and change variable to be lowercase for easy use.
if(data_validation(message) == True and query[0].lower() == "youtube"):
try:
if(data_validation(message) == True and query[1].lower() != "-d"):
# Removing the word "YouTube" and sending the results to the YouTube search engine.
for item in query[:]:
if(item.lower() == "youtube"):
query.remove(item)
search_query = ' '.join(query)
else:
pass #If it's not term we're looking to convert, ignore it.
# RAPID API for Youtube
try:
url = "https://youtube-search-results.p.rapidapi.com/youtube-search/"
querystring = {"q":search_query}
headers = {
"X-RapidAPI-Key": RAPID_KEY,
"X-RapidAPI-Host": "youtube-search-results.p.rapidapi.com"
}
response = requests.request("GET", url, headers=headers, params=querystring) # Grabbing response information from URL
request = json.loads(response.text) # Parsing json string for python use
# Testing to see if the RAPID API service responds and is online.
if(response.status_code == 503):
# If the service is not online, let the user know.
bot.send_message(message.chat.id, f"The RAPID API service appears to be offline try back later.\n")
if(response.status_code == 429):
# If the service has reached max quota for the day, let the user know.
bot.send_message(message.chat.id, f"Max quota reached, try back in 24 hours.\n")
# Grabbing first link from json text and sending direct url and title.
first_link = str((request["items"][0]["url"]))
bot.send_message(message.chat.id, f"{first_link}\n") # Sending first link that was queried.
# If there are no results found for the requested video, sending an error message to alert the user.
except:
bot.send_message(message.chat.id, "Unable to load video.\n")
except:
pass #ignoring if not the phrase we're looking for.
def test(message):
string = message.text.split()
print(string)
if(string[0] == "test" and data_validation(message) == True):
print("This is a test and i should be printed")
bot.send_message(message.chat.id, "Test message")
# Stay alive function for bot pinging / communication
bot.infinity_polling(1440)
The first problem in your code is your first line
from email import message
You import the message from email and also pass a parameter to the data_validation function with the same name, then return False in the data_validation function. If you return false, the function never will be executed.
first give an alias to first line you imported
Try This
from email import message as msg
import os
import re
import html
import json
import telebot
import requests
import http.client
from pytube import *
from dotenv import load_dotenv
load_dotenv()
# Creating hiding, and using API Keys
API_KEY = os.getenv("API_KEY")
RAPID_KEY = os.getenv("RAPID_API")
bot = telebot.TeleBot(API_KEY)
# Creating a help message for guidance on how to use bot.
#bot.message_handler(commands=["start"])
def help(message):
# Trying to send help message, if unable to send, throw an error message for the user.
try:
bot.send_message(message.chat.id, "Use \"Youtube\" and the video name to search for a video.\n")
except:
bot.send_message(message.chat.id, "There was an error fetching help, the bot may be offline.\n")
# Checking data and seeing if the word "YouTube" was used in order to start the search
def data_validation(message):
query = message.text.split()
print(query)
if("youtube" not in query[0].lower()): # Set flag false if regular text
return False # if you return false, the function never will be executed
else:
return True
# Searching for youtube videos
# using RAPID API
#bot.message_handler(func=data_validation)
def search(message):
query = message.text.split()
print(query) # if function executed you see the query result
# Check if data is valid, and change variable to be lowercase for easy use.
if(data_validation(message) == True and query[0].lower() == "youtube"):
try:
if(data_validation(message) == True and query[1].lower() != "-d"):
# Removing the word "YouTube" and sending the results to the YouTube search engine.
for item in query[:]:
if(item.lower() == "youtube"):
query.remove(item)
search_query = ' '.join(query)
else:
pass #If it's not term we're looking to convert, ignore it.
# RAPID API for Youtube
try:
url = "https://youtube-search-results.p.rapidapi.com/youtube-search/"
querystring = {"q":search_query}
headers = {
"X-RapidAPI-Key": RAPID_KEY,
"X-RapidAPI-Host": "youtube-search-results.p.rapidapi.com"
}
response = requests.request("GET", url, headers=headers, params=querystring) # Grabbing response information from URL
request = json.loads(response.text) # Parsing json string for python use
# Testing to see if the RAPID API service responds and is online.
if(response.status_code == 503):
# If the service is not online, let the user know.
bot.send_message(message.chat.id, f"The RAPID API service appears to be offline try back later.\n")
if(response.status_code == 429):
# If the service has reached max quota for the day, let the user know.
bot.send_message(message.chat.id, f"Max quota reached, try back in 24 hours.\n")
# Grabbing first link from json text and sending direct url and title.
first_link = str((request["items"][0]["url"]))
bot.send_message(message.chat.id, f"{first_link}\n") # Sending first link that was queried.
# If there are no results found for the requested video, sending an error message to alert the user.
except:
bot.send_message(message.chat.id, "Unable to load video.\n")
except:
pass #ignoring if not the phrase we're looking for.
def test(message):
string = message.text.split()
print(string)
if(string[0] == "test" and data_validation(message) == True):
print("This is a test and i should be printed")
bot.send_message(message.chat.id, "Test message")
# Stay alive function for bot pinging / communication
bot.infinity_polling(1440)
I found that using "if name == 'main':" and keeping all the functions in "main():" as a function handler everything ran smoothly.
I'm still trying to figure out why this works.
I'm aware I can use this
client.send_file(receiver, '/path/to/photo.jpg')
to send an image, but how can I attach a caption to the image?
According to the documentation just pass the value of the caption with a keyword argument like so client.send_file(chat, '/my/photos/me.jpg', caption="It's me!"). You can read the documentation here
While this question on how to send an image with caption to Telegram using Telethon was already answered concisely by #matthew-barlowe, (which I used to come to my own solution, thank you), I felt that it would be helpful to include a more comprehensive example using Telethon v3's new async API.
The code is documented and type hinted so it should provide it's own explanation. In the interest of keeping the example brief, capturing of exceptions is excluded.
import logging
from random import uniform
from time import sleep
from typing import Dict, List, Union
from telethon.sync import TelegramClient
logging.basicConfig(
format="[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s", level=logging.WARNING
)
# you should use dotenv module to extract credentials from the environment or .env file; 'pip install python-dotenv'
# do not store credentials in the file in production or git commit, this is only included for example purposes
SESSION_NAME = "sqlite-session"
TG_API_ID = 1234567890
TG_API_HASH = "*****"
CHANNEL_NAME = "yourchannelname"
CHANNEL_DISPLAY_NAME = "Your Channel Name"
CHANNEL_URL = "https://t.me/your-channel-name"
# define client
client = TelegramClient(SESSION_NAME, TG_API_ID, TG_API_HASH)
def create_message(data: Dict) -> str:
"""Formats a dictionary as a Telegram message.
:param data: Dict: A dictionary containing 'title', 'subtitle', 'text', 'url' and
'image_path' keys to be formatted as a message.
:return: str: A string including Markup to be sent as a message to a Telegram channel.
"""
# generate message
message = ""
if data.get("title", None):
message += f'**{data["title"]}**\n'
message += f'{data["subtitle"]}\n' if data.get("subtitle", None) else ""
if data.get("url", None):
message += data["url"]
message += "\n\n"
message += f"[{CHANNEL_DISPLAY_NAME}]({CHANNEL_URL})"
return message
async def channel_broadcast(
messages: Union[Dict, List[Dict]],
channel: str,
min_wait: float = 25.0,
max_wait: float = 120.0
) -> None:
""" Broadcasts a message to the specified Telegram channel. There will be a humanized wait in between postings.
:param messages: Union[Dict, List[Dict, ...]]: A dictionary or list of dicts containing 'title', 'subtitle',
'text', 'url' and 'image_path' keys to be formatted as a message.
:param channel: str: The name of the channel messages are to be broadcast to. You must have permission to
broadcast to this channel. See setup in telethon docs.
:param min_wait: float: Minimum wait between messages.
:param max_wait: float: Maximum wait between messages.
:return: None
"""
# ensure list
messages = [messages] if isinstance(messages, dict) else messages
for item in messages:
# generate a properly formatted message using markup and available fields
message = create_message(item)
# connect previously defined client
async with client:
await client.connect()
# send message if image is included
if item.get("image_path", None):
await client.send_file(
channel, item["image_path"], caption=message, link_preview=True
)
# send message without image
else:
await client.send_message(channel, message, link_preview=True)
# short blocking wait for multiple messages
# non-blocking waits are not in scope of this example
if len(messages) > 1:
sleep(uniform(min_wait, max_wait))
# you can provide a single dict or list of dicts
messages = [
{
"title": "First Message",
"subtitle": "This is the first message.",
"text": "This is a paragraph of text. The main idea of the message will be included here.",
"url": "https://test.com",
"image_path": "/path/to/a/local/image.png",
},
{
"title": "Second Message",
"subtitle": None,
"text": "This is a paragraph of text. The main idea of the message will be included here.",
"url": None,
},
]
# send all messages with a humanized wait between messages
with client:
client.loop.run_until_complete(
channel_broadcast(
messages, CHANNEL_NAME
)
)
'''
from coinbase.wallet.client import Client
from telegram import ParseMode
from telegram.ext import CommandHandler, Defaults, Updater
COINBASE_KEY = 'xxxxxxxxxxxx'
COINBASE_SECRET = 'xxxxxxxxxxxx'
TELEGRAM_TOKEN = 'xxxxxxxxxxxx'
coinbase_client = Client(COINBASE_KEY, COINBASE_SECRET)
#if __name__ == '__main__':
updater = Updater(token=TELEGRAM_TOKEN, defaults=Defaults(parse_mode=ParseMode.HTML))
dispatcher = updater.dispatcher
dispatcher.add_handler('start', startCommand) # Accessed via /start
dispatcher.add_handler('alert', priceAlert) # Accessed via /alert
updater.start_polling() # Start the bot
updater.idle() # Wait for the script to be stopped, this will stop the bot
def startCommand(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text='Hello there!')
def priceAlert(update, context):
if len(context.args) > 2:
crypto = context.args[0].upper()
sign = context.args[1]
price = context.args[2]
context.job_queue.run_repeating(priceAlertCallback, interval=15, first=15, context=[crypto, sign, price, update.message.chat_id])
response = f"⏳ I will send you a message when the price of {crypto} reaches £{price}, \n"
response += f"the current price of {crypto} is £{coinbase_client.get_spot_price(currency_pair=crypto + '-GBP')['amount']}"
else:
response = '⚠️ Please provide a crypto code and a price value: \n<i>/price_alert {crypto code} {> / <} {price}</i>'
context.bot.send_message(chat_id=update.effective_chat.id, text=response)
def priceAlertCallback(context):
crypto = context.job.context[0]
sign = context.job.context[1]
price = context.job.context[2]
chat_id = context.job.context[3]
send = False
spot_price = coinbase_client.get_spot_price(currency_pair=crypto + '-GBP')['amount']
if sign == '<':
if float(price) >= float(spot_price):
send = True
else:
if float(price) <= float(spot_price):
send = True
if send:
response = f'👋 {crypto} has surpassed £{price} and has just reached <b>£{spot_price}</b>!'
context.job.schedule_removal()
context.bot.send_message(chat_id=chat_id, text=response)
enter image description here
I get this error of the code above, also I have already tried changing the position of the def but, it also shows error, How to solve this?
It is the code for telegram bot and also this keeps on showing me NameError, I have already added python3 and pip, but still not solved
Python reads files top to bottom. So when you call dispatcher.add_handler('start', startCommand), the function startCommand is not yet known. Move the part
updater = Updater(token=TELEGRAM_TOKEN, defaults=Defaults(parse_mode=ParseMode.HTML))
dispatcher = updater.dispatcher
dispatcher.add_handler('start', startCommand) # Accessed via /start
dispatcher.add_handler('alert', priceAlert) # Accessed via /alert
updater.start_polling() # Start the bot
updater.idle() # Wait for the script to be stopped, this will stop the bot
below the callback definitions.
Apart from that, add_handler needs a Handler as argument, in your case something like add_handler(CommandHanlder('start', startCommand). Please see PTB tutorial as well as the examples.
Disclaimer: I'm the current maintainer of the python-telegram-bot library.
Try
dispatcher.add_handler('start', startCommand()) # Accessed via /start
dispatcher.add_handler('alert', priceAlert()) # Accessed via /alert
You will also need to add the two arguments required by both functions.
dispatcher.add_handler('start', startCommand(update, context))
dispatcher.add_handler('alert', startCommand(update, context))
I'm not exactly sure what data the two functions take in but I'm going to guess that it is whatever the bot is returning.
I have been trying since the morning but earlier there were errors, so i had the direction but now there is no error and even not a warning too..
How code looks like :
import requests
def send_msg(text):
token = "TOKEN"
chat_id = "CHATID"
url_req = "https://api.telegram.org/bot" + token + "/sendMessage" + "?chat_id=" + chat_id + "&text=" + text
results = requests.get(url_req)
print(results.json())
send_msg("hi there 1234")
What is expected output :
It should send a text message
What is the current output :
It prints nothing
It would be great help is someone helps, Thank you all
Edit : 2
As the below dependancies were not installed, it was not capable of sending the text .
$ pip install flask
$ pip install python-telegram-bot
$ pip install requests
Now can somebody help me with sendPhoto please? I think it is not capable of sending image via URL, Thank you all
**Edit 3 **
I found a image or video sharing url from here but mine image is local one and not from the remote server
There is nothing wrong with your code. All you need to do is proper indentation.
This error primarily occurs because there are space or tab errors in
your code. Since Python uses procedural language, you may experience
this error if you have not placed the tabs/spaces correctly.
Run the below code. It will work fine :
import requests
def send_msg(text):
token = "your_token"
chat_id = "your_chatId"
url_req = "https://api.telegram.org/bot" + token + "/sendMessage" + "?chat_id=" + chat_id + "&text=" + text
results = requests.get(url_req)
print(results.json())
send_msg("Hello there!")
To send a picture might be easier using bot library : bot.sendPhoto(chat_id, 'URL')
Note : It's a good idea to configure your editor to make tabs and spaces visible to avoid such errors.
This works for me:
import telegram
#token that can be generated talking with #BotFather on telegram
my_token = ''
def send(msg, chat_id, token=my_token):
"""
Send a mensage to a telegram user specified on chatId
chat_id must be a number!
"""
bot = telegram.Bot(token=token)
bot.sendMessage(chat_id=chat_id, text=msg)
Here is an example that correctly encoded URL parameters using the popular requests library. This is a simple method if you simply want to send out plain-text or Markdown-formatted alert messages.
import requests
def send_message(text):
token = config.TELEGRAM_API_KEY
chat_id = config.TELEGRAM_CHAT_ID
url = f"https://api.telegram.org/bot{token}/sendMessage"
params = {
"chat_id": chat_id,
"text": text,
}
resp = requests.get(url, params=params)
# Throw an exception if Telegram API fails
resp.raise_for_status()
For full example and more information on how to set up a Telegram bot for a group chat, see README here.
Below is also the same using asyncio and aiohttp client, with throttling the messages by catching HTTP code 429. Telegram will kick out the bot if you do not throttle correctly.
import asyncio
import logging
import aiohttp
from order_book_recorder import config
logger = logging.getLogger(__name__)
def is_enabled() -> bool:
return config.TELEGRAM_CHAT_ID and config.TELEGRAM_API_KEY
async def send_message(text, throttle_delay=3.0):
token = config.TELEGRAM_API_KEY
chat_id = config.TELEGRAM_CHAT_ID
url = f"https://api.telegram.org/bot{token}/sendMessage"
params = {
"chat_id": chat_id,
"text": text,
}
attempts = 10
while attempts >= 0:
async with aiohttp.ClientSession() as session:
async with session.get(url, params=params) as resp:
if resp.status == 200:
return
elif resp.status == 429:
logger.warning("Throttling Telegram, attempts %d", attempts)
attempts -= 1
await asyncio.sleep(throttle_delay)
continue
else:
logger.error("Got Telegram response: %s", resp)
raise RuntimeError(f"Bad HTTP response: {resp}")
I am using python-slackclient and messages I am sending are not being formatted and channel and usernames are not being linked. I tried both RTM and also API call, in both cases it fails.
Here is my code:
from slackclient import SlackClient
token = 'token'
sc = SlackClient(token)
team_join_event = 'team_join'
message = ('Hi! \n\nPublic channel - <#C06VBR8UT|general>\n\n'
'Private channel #sports.\n\n Admin - <#U06VBQ8TB|v>')
if sc.rtm_connect():
user_id = 'U2T0SF1U0'
response = sc.api_call('im.open', user=user_id)
dm_channel_id = response['channel']['id']
# sc.rtm_send_message(dm_channel_id, message)
sc.api_call(
'chat.postMessage', channel=dm_channel_id, text=message,
link_names=1)
else:
print ("Connection Failed, invalid token?")
Here is how it appears: