From the previous "I tried using Slackbot after studying Python3" We have improved or added features.
Using the Gurunavi API, enter a search word in slack and return the hit URL. If you type "rice Shinagawa yakitori", the URL of a restaurant that looks like a yakitori restaurant in Shinagawa will be returned. Since I was searching by address when searching by location keyword, the result of the location different from the actual image is returned, so I changed to the search using the area master.
This is a store name search using the Gurunavi API. If you type "Shop Shinagawa LOL", the URL of Shinagawa LOL will be returned. It is simply a store name search. However, we cannot handle cases where there is a space between them.
Use Yahoo's Geocoder API and Static Map API to return a rain cloud radar image.
If you type "rain Shinagawa", a map image with rain clouds near Shinagawa will be returned. To return a map image, use Slack's API files.upload
.
I used Pillow to work with image files.
slackbot/ ├ plugins/ │ └ slackbot_restapi.py │ └ restapi.py │ └ gnaviapi.py │ └ run.py └ slackbot_settings.py └ Procfile (File for Heroku) └ runtime.txt (File for Heroku)
It hasn't changed in particular. I am modifying gnaviapi.py and slackbot_restapi.py. However, classification and somehow organizing are not divided w I think I can write it a little more beautifully.
This time only the changes. Unlike the last time, it is an explanation for each specification.
slackbot_restapi.py
"""
Plugin Program
"""
from io import BytesIO
import requests
from requests.exceptions import RequestException
from PIL import Image
from slackbot.bot import listen_to
from plugins.restapi import RestApi
from plugins.gnaviapi import GnaviApi
import slackbot_settings
@listen_to('rice')
@listen_to('shop')
def search_restraunt(message):
"""
Search Gurunavi based on the received message and return the URL.
Location: Area M Master Code(areacode_m)or address(address)
Keywords: free words(freeword)or store name(name)
"""
url = 'https://api.gnavi.co.jp/RestSearchAPI/20150630/'
key = 'YOUR_GNAVI_API_TOKEN'
gnavi = GnaviApi(url, key)
search_word = message.body['text'].split()
if len(search_word) >= 3:
try:
params = gnavi.create_params(search_word)
gnavi.garea_middle_fech()
search_area = gnavi.garea_middle_search(search_word[1])
if len(search_area) == 0:
search_area = {'address': search_word[1]}
params.update(search_area)
gnavi.api_request(params)
for rest_url in gnavi.url_list():
message.send(rest_url)
except RequestException:
message.send('I didn't get into Gurunavi, so look for it again later ...( ´Д`)y━ ・~~')
return
except Exception as other:
message.send(''.join(other.args))
return
else:
message.send('↓ I want you to search like this ...( ̄Д ̄)No')
message.send('Rice place keyword (characters are separated by spaces)')
message.send('Example) Rice Shinagawa Yakitori')
With params = gnavi.create_params (search_word)
, it judges "rice" or "store" and switches the parameter to be thrown to the API to free word or store name.
Use garea_middle_fech ()
to search the Gurunavi area M master and get the area code.
garea_middle_search (search_word [1])
returns the first area code that matches the place name entered in Slack.
If you can't get the area code, we'll continue to search for your address.
The rest is the same as last time.
gnavapi.py
"""
Gurunavi API
"""
# -*- coding: utf-8 -*-
from requests.exceptions import RequestException
from plugins.restapi import RestApi
class GnaviApi(RestApi):
"""
Gurunavi API class
"""
def __init__(self, url, key):
super().__init__(url)
self.key = key
self.garea_s = None
def create_params(self, search_word):
"""
Change API parameters according to the keywords entered in Slack.
"""
params = {
'format': 'json'
}
if search_word[0] == 'rice':
params['freeword'] = search_word[2]
elif search_word[0] == 'shop':
params['name'] = search_word[2]
return params
def url_list(self):
"""
Create a list of restaurant URLs from Response and return it.
"""
json_data = self.response_data.json()
if 'error' in json_data:
raise Exception('I couldn't find it with that keyword ...(´ ・ ω ・ `)')
if json_data['total_hit_count'] == '1':
return [(json_data['rest'])['url']]
else:
return [rest_data['url'] for rest_data in json_data['rest']]
def garea_middle_fech(self):
"""
Get the area M master from the Gurunavi API.
"""
garea = RestApi('https://api.gnavi.co.jp/master/GAreaMiddleSearchAPI/20150630/')
params = {
'keyid': self.key,
'format': 'json',
'lang': 'ja'
}
try:
garea.api_request(params)
self.garea_s = garea.response_data.json()
if 'error' in self.garea_s:
raise Exception('I don't know the place ...(´ ・ ω ・ `)')
except RequestException:
raise RequestException()
def garea_middle_search(self, area_name):
"""
From within the area M master, area_Get the value that matches name.
(Because it is strict if it is an exact match, it is a partial match.)
"""
result_dict = {}
for area_s in self.garea_s['garea_middle']:
if area_s['areaname_m'].find(area_name) >= 0:
result_dict = {'areacode_m': area_s['areacode_m']}
break
return result_dict
↑ A method to find the area master has been added to the Gurunavi API class.
slackbot_restapi.py
"""
Plugin Program
"""
from io import BytesIO
import requests
from requests.exceptions import RequestException
from PIL import Image
from slackbot.bot import listen_to
from plugins.restapi import RestApi
from plugins.gnaviapi import GnaviApi
import slackbot_settings
def search_restraunt(message):
"""
abridgement!!!
"""
@listen_to('rain')
def search_weather(message):
"""
Get latitude / longitude from Geocoder API based on received message.
Returns a rain cloud radar image from the static map API based on latitude and longitude.
Location: Address(query)
"""
url_geocoder = 'https://map.yahooapis.jp/geocode/V1/geoCoder'
url_staticmap = 'https://map.yahooapis.jp/map/V1/static'
key_yahoo = 'YOUR_YAHOO_API_TOKEN'
url_slackapi = 'https://slack.com/api/files.upload'
geocoder_api = RestApi(url_geocoder)
staticmap_api = RestApi(url_staticmap)
search_word = message.body['text'].split()
try:
geocoder_api_params = {
'appid': key_yahoo,
'query': search_word[1],
'output': 'json'
}
geocoder_api.api_request(geocoder_api_params)
geocoder_json = geocoder_api.response_data.json()
if 'Error' in geocoder_json:
raise Exception('I don't know the place ...(´ ・ ω ・ `)')
coordinates = (((geocoder_json['Feature'])[0])['Geometry'])['Coordinates']
staticmap_api_params = {
'appid': key_yahoo,
'lon': (coordinates.split(','))[0],
'lat': (coordinates.split(','))[1],
'overlay': 'type:rainfall',
'output': 'jpg',
'z': '13'
}
staticmap_api.api_request(staticmap_api_params)
slackapi_params = {
'token': slackbot_settings.API_TOKEN,
'channels': 'C5CJE5YBA'
}
image_obj = Image.open(BytesIO(staticmap_api.response_data.content), 'r')
image_obj.save('/tmp/weather.jpg')
with open('/tmp/weather.jpg', 'rb') as weatherfile:
requests.post(url_slackapi, data=slackapi_params, files={
'file': ('weather.jpg', weatherfile, 'image/jpeg')})
except Exception as other:
message.send(''.join(other.args))
return
Unlike the Gurunavi API, the area master does not seem to exist, so the latitude and longitude are acquired based on the address. Once you have the latitude and longitude, the rest is easy. It was easy to get the image data ** "obtain" **. So far ...
From here, I was addicted to it.
I was worried that I couldn't upload image data to Slack.
At first I thought I would go if I sent ʻimage_obj = Image.open (BytesIO (staticmap_api.response_data.content),'r'), but it's totally useless. As a result of various trials, I succeeded in saving the actual file once, reading it with kʻopen ()
, and sending the data.
Heroku seems to be able to save files under / tmp
, so I saved it as ʻimage_obj.save ('/tmp/weather.jpg')` and reloaded it.
Since ʻimage_obj was a
JpgImageFileobject, it would be the same as the
fileobject, is it the cause of the defeat? I was worried about 3 days after setting
PngImageFile or ʻimage_obj = BytesIO (staticmap_api.response_data.content)
and then using getvalue ()
and getbuffer ()
.
I'm checking the spec of requests.post ()
, but I don't know why the JpgImageFile
can't be sent. I will continue to investigate, but if anyone knows, please let me know.
Thank you for your comment
Change before
image_obj = Image.open(BytesIO(staticmap_api.response_data.content), 'r')
image_obj.save('/tmp/weather.jpg')
with open('/tmp/weather.jpg', 'rb') as weatherfile:
requests.post(url_slackapi, data=slackapi_params, files={
'file': ('weather.jpg', weatherfile, 'image/jpeg')})
This part,
After change
output = BytesIO()
image_obj = Image.open(BytesIO(staticmap_api.response_data.content), 'r')
image_obj.save(output, 'jpeg')
requests.post(slackbot_settings.API_URL, data=slackapi_params, files={
'file': ('weather.jpg', output.getvalue(), 'image/jpeg')
})
I corrected it and moved it, and it worked! Why didn't it work as it is? Anyway, thank you!
Recommended Posts