Continuation ・ I tried to make Slackbot after studying Python3

Introduction

From the previous "I tried using Slackbot after studying Python3" We have improved or added features.

specification

  1. 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.

  2. 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.

  3. 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.

Environment etc.

I used Pillow to work with image files.

Constitution

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.

Implementation

This time only the changes. Unlike the last time, it is an explanation for each specification.

Store search

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.

Nimbus search

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 thefileobject, is it the cause of the defeat? I was worried about 3 days after settingPngImageFile or ʻimage_obj = BytesIO (staticmap_api.response_data.content) and then using getvalue () and getbuffer ().

スクリーンショット 2017-06-01 23.27.30.png

At the end

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.

Postscript (20170701)

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

Continuation ・ I tried to make Slackbot after studying Python3
After studying Python3, I made a Slackbot
I tried to touch Python (installation)
I tried to make various "dummy data" with Python faker
I tried to make a stopwatch using tkinter in python
I tried to make GUI tic-tac-toe with Python and Tkinter
I tried to summarize Python exception handling
I tried to implement PLSA in Python
I tried to implement permutation in Python
[Python] I tried to implement stable sorting, so make a note
I tried to make a regular expression of "time" using Python
I tried to implement PLSA in Python 2
[3rd] I tried to make a certain authenticator-like tool with python
Python3 standard input I tried to summarize
I tried to make a regular expression of "date" using Python
I tried to make a periodical process with Selenium and Python
I tried to implement ADALINE in Python
I tried to make a 2channel post notification application with Python
I tried to implement PPO in Python
I tried to make a todo application using bottle with python
[4th] I tried to make a certain authenticator-like tool with python
[Python] Simple Japanese ⇒ I tried to make an English translation tool
I tried to make a Web API
[Python] I tried to calculate TF-IDF steadily
[1st] I tried to make a certain authenticator-like tool with python
I tried to touch Python (basic syntax)
I tried to make an image similarity function with Python + OpenCV
[TCP / IP] After studying, try to make an HTTP client-like with Python
Python: I tried to make a flat / flat_map just right with a generator
[AWS] [GCP] I tried to make cloud services easy to use with Python
I tried to make a traffic light-like with Raspberry Pi 4 (Python edition)
[Zaif] I tried to make it easy to trade virtual currencies with Python
I refactored "I tried to make Othello AI when programming beginners studied python"
I want to make a game with Python
I tried to get CloudWatch data with Python
I tried to output LLVM IR with Python
I tried to make AI for Smash Bros.
I tried to implement TOPIC MODEL in Python
I tried to automate sushi making with python
I want to make C ++ code from Python code!
I tried to implement selection sort in python
I tried to make a ○ ✕ game using TensorFlow
I tried Python> autopep8
I tried to debug.
I tried to paste
I tried Python> decorator
I tried to make a simple mail sending application with tkinter of Python
[Patent analysis] I tried to make a patent map with Python without spending money
Python / PEP8> E128 I tried to solve continuation line under-indented for visual indent
[Python] I tried to make a Shiritori AI that enhances vocabulary through battles
[Introduction to Docker] I tried to summarize various Docker knowledge obtained by studying (Windows / Python)
I tried to make a "fucking big literary converter"
I tried to graph the packages installed in Python
When I tried to introduce python3 to atom, I got stuck
I tried to summarize how to use matplotlib of python
I tried to implement Minesweeper on terminal with python
I tried to get started with blender python script_Part 01
I tried to touch the CSV file with Python
I tried to draw a route map with Python
I tried to solve the soma cube with python
I tried to implement a pseudo pachislot in Python