[PYTHON] Now in Singapore The story of creating a LineBot and wanting to do a memorable job

"Sorry, I can't go to the class"

This CM has a strong impact. I love this so when I invite him to a class meeting "** I'm in Singapore now **" I have created a ** LineBot ** that will reply to you. In addition, various specifications have been added to further enhance the ** doya feeling **. Even if it doesn't remain on the map, I want to make it a ** memorable job ** for the person who used it!

This is the 4th day of Fucking App Advent Calendar 2019. ~~, a feeling of a fucking app that drifts from the title without writing ~~

How to use:

① ** Hold a class meeting ** ② ** Start Line and ask "Ayano, where are you now?" ** ③ ** "I'm sorry, I can't attend the class meeting ~~~ I'll omit the following" ** ④ ** Everyone looks into it with the feeling that "Eh, Singapore" **

State when executed:


If you want to run it at hand, please register as a friend here.

Add friend QR_min.PNG

"I'm in Singapore now"

For those who haven't seen it yet, please see the CM itself below.

[Taisei Corporation CM: "Singapore" version (youtube)](https://www.youtube.com/watch?v= HQYQ3Me2KLw) https://www.youtube.com/watch?v=HQYQ3Me2KLw

"Jobs that remain on the map"

It implements various ~~ extra ~~ functions. The first is "** Jobs that remain on the map **".

**Singapore! !! To make ** more appealing I kindly tried to show a map showing the location of Singapore. With this, ** the feeling that remains on the map ** is perfect ☆

In addition, the international AYANO ** Fly around over 200 countries and regions (awesome) ** If you ask a question other than a fixed phrase, She is not always in Singapore. You will hear replies from various places! キャプチャ1-2.PNG

Because you can find the location even with an unfamiliar country name ** It's also an app for studying world geography! ** ** ~~ It may not have been a fucking app. ~~

Respond to various invitations such as drinking parties and farewell parties

Oops, if you look closely, in the screen capture above It seems that he is inviting him to a "class reunion". ** Immediately respond to the content of the invited party **!

Please invite anything, whether it's "** Gokon " or " Sakura wo Miru Kai **".

Creating Laputa (~~ Not left on the map ~~)

AYANO also makes things other than the subway. キャプチャ2-1.PNG

We are making various things besides Laputa! Please check for yourself the various other creations. ~~ Put someone's youth on = Theta & Pazu. Put you on. ~~

Function that responds to your keywords (morphological analysis)

Although we will respond according to the content of the invitation such as the second party, With the functions so far, there is a "random message display feeling", Maybe to a friend who looked into me together "** Oh, isn't this AYANO a bot? **" It may be bald.

So, in response to the keywords of the conversation you threw, Something ** added a function to return meaningful words **. (Red frame) キャプチャ_ラーメン.PNG ~~ Highly conscious conversation. It seems that ramen is nostalgic. ~~

Of course AYANO can understand Japanese, so ** You can recognize the "important words" that appear in the conversation. ** ** This time, I recognized that "noun / general" was important. If it doesn't exist, it will reply "Jobs that remain on the map". In the above example, it seems that it recognizes "ramen". ** This creates reality for AYANO and is memorable! ** **

Morphological analysis itself is no longer a terrific technique. However, the implementation to be built into GAE (like Serverless / AWS Lambda) The point is that it is not very familiar (it is a little difficult to realize). ** There is no external API call, and it is explosive. Super immediate less ☆ **

** Now, at various places such as class meetings and drinking parties ** ** You can now talk with AYANO all over the world ☆ **

** When used with friends, it can be seen with warm white eyes, ** ** There is no doubt that it will be a "memorable job" ☆ **

So that's all for the introduction of the contents Implementation ideas, code, I will write various know-how on creating LineBot below.

It's long.

Implementation points: Table of contents / summary

  1. Points of the whole method
  2. Reference material that is the basis of the whole
  3. LineBot requires HTTPS. Let's make it with GAE
  4. LineBot Reply is free. Push is charged. Let's make it only with Reply
  5. The secret behind the Line Messaging API
  6. The trick to use "access token" permanently
  7. The trick to deceive "connection confirmation"
  8. A little complicated trick to "display a map"
  9. The story that "wait" could not be realized
  10. How to escape from the restrictions of GAE (Google App Engine)
  11. Natural language processing is too heavy to work normally for free
  12. The story when it works locally but not on GAE

1. Points of the whole method

1-1. Reference materials that form the basis of the whole

First of all, how do you make LineBot in the first place? So, please refer to the following page. (This is an article on the development blog of people in Line.)

I made a bot that can keep up with the last train using image map messages

The base configuration will be created in the same way as this article. ** Python + Flask ** (However, the Python version has changed from 3.6 to 3.7) And the map image uses ** Google Static Maps API ** as well as the article.

First of all, it is a good idea to deploy "Aum Return Bot". However, ** just writing and executing this code does not make it a LineBot **. How should I move it?

1-2. LineBot is premised on HTTPS. Let's make it with GAE

Most of the information about making LineBot seems to be deployed on ** Heroku **. The reason for using Heroku is ** because it's easy to use HTTPS **.

To create a LineBot, first log in to LINE Developers. (You can use your own Line account as it is)

There is a place to specify "Webhook URL" after login, Only ** HTTPS can be specified to specify the URL **. Also, when specifying an image file for transmission in the code, etc. The Line Messaging API requires ** HTTPS-URL to be specified **. (You cannot send a local file. Be sure to specify it by URL)

In other words, creating an HTTPS server is almost essential for ** LineBot development **.

There are three main options here. ① ** Set up your own server and make it HTTPS ** ② ** Use serverless / PaaS service ** (Heroku, GAE, Lambda, etc.) ③ Use a dedicated service such as ** Twilio ** and have them take charge of the server part

③ is the most recommended for simple response bots. This time I'm writing a little complicated code myself, so it's either ① or ②. Although ① can be realized for free, server preparation / operation is a little troublesome. Therefore, ② is the best option.

Probably because of the Line official example and the above reasons Information on how to make most LineBots It seems that Heroku is a prerequisite. However, ** essentially anything is fine as long as HTTPS can be easily realized **, so There are no elements that depend on Heroku.

This time I changed my mind a little I would like to use ** GAE (GoogleAppEngine) **. The code for the article for Heroku works pretty well.

GAE's Python 3 run lime is Python 3.7 only, so that's a change

** GAE (Standard Environment) has a 28-hour free tier at all times per day. ** ** (As of November 2019) Hey, I think it's 24 hours a day, right? When multiple instances are launched at the same time depending on the load status, If you launch a better instance in terms of performance It is a mechanism that counts multiple minutes of time. In other words, if the load can be processed by one instance with the minimum configuration, Even if there are a few at the peak The image is that it always fits in a free frame.

Always free = Apart from the free coupon for 30,000 yen that can be used for the first year with GCP

The range of use that can be used free of charge even after one year. For example, "Qiita Hall of Fame" uses this always-free tier in IaaS.

Run the GAE Python 3.7 Flask tutorial (Just git clone and gcloud app deploy and it's done right away) If you change main.py to the reference code, the LineBot is almost complete. (Also, add line-bot-sdk == 1.14.0 to requirements.txt)

1-3. LineBot Reply is free. Push is charged. Let's make it only with Reply

The best way to use the Line Messaging API in personal development is It seems to be ** designing a service with Reply **.

The LineMessagingAPI has a pay-as-you-go limit for sending Push-type messages. With the free tier, you can only send 1000 messages a month. Even if you charge, if you exceed a certain number, you will be charged for about 3 to 5 yen per copy. (For details, please check the official website / latest information etc.)

However, ** Reply can be used for free **.

As the first design of the big picture of the service ** "Service design that makes it natural to reply to utterances from users" ** It would be desirable to have a form that does not depend on Push-type transmission.

However, Reply can only be used for a certain period of time after the user speaks. Only reply once for one utterance & only 5 balloons at a time, It is also important to note that it can only be used.

For example, if you want to make an "** counting prime number and calming app **", If the bot unilaterally talks to 13, 17, 19 ... every 3 seconds, It will be a Push type. next? next? Ask the user each time So that it is natural to have them answer 23, 29, etc. It is better to think about the design of the entire service.

This time AYANO said, "Let's go to the class meeting!" Just as it is quite natural to reply to an invitation It fits in the service design!

2. The secret behind the Line Messaging API

2-1. The secret trick to use "access token" permanently

The following locations of the reference source article, For "YOUR_CHANNEL_ACCESS_TOKEN",

line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')

Free / can be issued as many times as you like on LINE Developers Set the "Channel Access Token (Long Term)". It's at the bottom of "Messaging API Settings".

But this access token is It is necessary to set the expiration date at the time of issuance, "Time until the current channel access token becomes invalid" ** You can only set up to 24 hours with the pull-down **.

Normally, set it to 24 hours, and at a pace of about every 23 hours. I need to create an extension / rewrite process, Here is the ** real trick ** (at the level of wondering if it's okay to write).

If you set ** time = 0, it will be a permanently valid token **. (As of November 2019)

** Awesomely fast ~~ Knifehand strike ~~ If you don't have me, you'll miss it ** With that in mind, let's thank you for using it. (This line is a complete death flag)

It's not a Line bug, but the access token expiration date is It seems that it was indefinite at the beginning. Changing to put a time limit, A transitional period of that change? Many oppositions take time to change? Seems like For that, basically set the effective time, It seems that the situation is that people who know it can use it infinitely. (Including rumor & evil guess. Truth unknown)

I don't know the best way to automate the expiration of this token, (I want to make serverless basically stateless) Should I stop developing LineBot just because there is a deadline for this guy? Because it was a critical point that I thought ** I sincerely hope that you will continue to use it indefinitely **.

2-2. The trick to deceive "connection confirmation"

This is usually from LINE Developers It's a story that is half buggy. (As of November 2019)

As mentioned above, in the "Webhook URL" of LINE Developes, The GAE URL will be listed as the HTTPS URL. Is not OK even if I press the "Confirm connection" button.

So, in the handle definition of the original code, as follows Add a processing branch with a special reply_token.

#The following is the handle definition
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    #Special code to make "connection confirmation" of Line OK
    #When you press "Check Connection" on Line's Developer Console
    #If you make it normally, reply_500 returns due to illegal token.
    #I get angry if the expected 200 is not returned on the connection confirmation side.
    #Problems on Line's console as of November 2019. Probably will be resolved eventually.
    if event.reply_token == "00000000000000000000000000000000":
    #Omitted below

It does not mean that it will not work unless the "connection confirmation" is passed. However, it's still a matter of mood, so I want to make connection confirmation = OK. For more information, see the great pioneer Qiita article below.

About the error when checking the connection of the LINE Developes Webhook URL

2-3. A little complicated trick to "display a map"

The most confusing process in this development is The process of displaying a map, that is, It is a process to send the result of ** Google Static Maps API ** to Line.

First, what is the Google Static Maps API? With the map API provided by Google A thing that made Google MAP a static image It can be obtained by specifying simple parameters.

What is amazing is not only the designation by latitude and longitude, but also Singapore, Yokohama, etc. It also supports returning coordinates by specifying it with a place name. A list of countries and regions around the world where AYANO is flying It has information in a simple LIST type. Even if you don't have GPS coordinates in that LIST Just throw the country name into the Google Static Maps API, You are telling us the coordinates. Easy. Please google for other detailed options as appropriate.

So ** How do I send that Google Static Maps API image to Line? ** **

LineMessagingAPI has an API for sending images, Please specify the image for sending with the URL of https, Is written in the reference.

And the Google Static Maps API Access the static map image over HTTPS.

** Google Static Maps API URL ** ** You can specify it as an argument of LineMessagingAPI! ** ** ** ⇒ Lost. ** **

The URL for the Google Static Maps API is HTTPS. But the image file doesn't "exist" directly in that path, Because it is calculated and displayed in Google ** Seen from the Line side, it's not an image, right? It seems that it looks like ** ** This method doesn't seem to work. ** ** (* The exact reason why it doesn't work can only be understood by asking the person inside. Maybe because the API key is also included in the URL parameter I thought it would be impossible because of that certification.)

Therefore, only the images created by Google Static Maps API It seems to be displayed in a pseudo manner on my own server (this time on GAE) You need to have the code ready. This is the part of the code part described later.

def imagemap(url, size):
#The following is omitted

The same is done in the base article of the reference source. At first glance, I didn't quite understand the intent of the code, so I added a commentary.

Furthermore, as a result of adjusting the processing so that any designated Japanese point can be displayed, If you add excerpts and comments only to the key points, It will be as follows.

#■ Google Map related settings
#Enter the key for Google's Static Maps API.
google_staticmaps_api_key="YOUR GOOGLE STATICMAPS API KEY"
#Specify the size to use when sending with Google (* Maximum 640 on Googles side*Up to 640)

#markers=Enter the country name and automatically search and display
#https://maps.googleapis.com/maps/api/staticmap?markers=color:blue|%22%E3%82%B7%E3%83%B3%E3%82%AC%E3%83%9D%E3%83%BC%E3%83%AB%22&size=300x300&zoom=3&language=jp&key=YOUR GOOGLE STATICMAPS API KEY

#input_Since basyo is entered in Japanese, it will be returned after URL encoding.
def makeMapUlr(input_basyo):
    map_image_url = 'https://maps.googleapis.com/maps/api/staticmap?markers=color:{}|{}&center={}&zoom=3&language=jp&size={}x{}&key={}'.format('blue', urllib.parse.quote(input_basyo), urllib.parse.quote(input_basyo),IMAGE_SIZE, IMAGE_SIZE, google_staticmaps_api_key)
    return map_image_url

#Function to process into a message for displaying a map of Line
def makeImagemapSendMessage(map_image_url):
    #Flask host name will be entered:
    request_host_name = request.host
    base_url = 'https://{}/imagemap/{}'.format(request_host_name, urllib.parse.quote_plus(map_image_url))
    message = ImagemapSendMessage(
        base_url = base_url,
        alt_text = 'world map',
        base_size = BaseSize(height=IMAGE_SIZE, width=IMAGE_SIZE),
    return message
#Performs the process of returning the image acquired from Google based on the received request.
def imagemap(url, size):
    #For debugging
    map_image_url = urllib.parse.unquote(url)
    response = requests.get(map_image_url)
    img = Image.open(BytesIO(response.content))
    img_resize = img.resize((int(size), int(size)))
    byte_io = BytesIO()
    img_resize.save(byte_io, 'PNG')
    return send_file(byte_io, mimetype='image/png')

#Using the code above,
# line_bot_api.reply_message
#Of the argument of, reply_Just make a message equivalent and pass it
#(The return value of makeImagemapSendMessage is that)
#    line_bot_api.reply_message(
#        event.reply_token,
#        reply_messages
#    )

** Specify the image with the HTTPS URL, ** ** But you can't just enter the URL of Google Static Maps. ** ** I think this is ** super addictive **.

2-4. The story that "wait" could not be realized

By the way, this time AYANO ** As I was waiting for a classmate invitation ** ** And prepare a map of Singapore ** ** I will reply to you with a super-immediate reply. ** ** To that extent, I was invited to the class meeting ** Don't bite too much **, Isn't it possible to return it naturally every 10 seconds?

In conclusion, I couldn't. (I didn't understand)

What if I reply more than once with wait? ⇒ It seems that reply_token can only be used once.

Is it possible to specify the interval and wait in the LineMessagingAPI? ⇒ Reference does not seem to be there

Furthermore, if you wait GAE: I feel that it is structurally incompatible with serverless. (I don't think the billing amount will increase significantly. It's a matter of mood)

As a last resort, if you reply first, then wait and then push, It's not impossible. As mentioned above, Push is expensive, so I rejected it.

This time, ** AYANO who was waiting for the invitation of the classmate ** Please forgive me with the setting. ** Appeal Singapore with super-immediate less **.

3. How to escape from the restrictions of GAE (Google App Engine)

3-1. Natural language processing is too heavy to work normally for free

Natural language processing x Python is Mecab, Janome, Also, I often used libraries such as Gensim in Word2Vec.

By making a chatbot, I would like to use these libraries / functions as well.

However, a big wall stands here. ** GAE can only use libraries that are lightweight to install (explanatory miscellaneous) **

Although Mecab gave up from the beginning, Janome and Gensim also Even if you adjust the memory size of the instance to the maximum It could not be used on GAE due to memory over. With a little ingenuity, it's unlikely that it will be free.

** Therefore, as a morphological analysis tool that can be used even with the smallest instance of GAE ** ** I tried using "igo-python". ** ** It's lightweight, it moves quickly, and it's wonderful.

The usage is the same as Mecab and Janome, as shown in the code below. However, this time the dictionary etc. have not been expanded, It should be noted that the accuracy of morphological analysis is quite low.

igo-How to use python

from igo.Tagger import Tagger

#Morphological analysis: igo-Initialization of python
t = Tagger()

#Function that returns the morphological analysis result as a character string
def extract_str(input_str):
    parsed_list = t.parse(input_str)
    result_str = ""
    for m in parsed_list:
        result_str += m.surface + " / " + m.feature + " \n"
    return result_str

#noun-A function that extracts only the general and returns it as a list
def meisi_tyuusyutu(input_str):
    result_list = []
    parsed_list = t.parse(input_str)
    for m in parsed_list:
        feature_list = m.feature.split(',')
        #noun-General, particles-Attributive form, particle-It becomes like a particle.
        hinsi_info = feature_list[0] + "-" + feature_list[1]
        if hinsi_info == "noun-General":
    return result_list

Setting method when deploying to GAE, How to write "requirements.txt" is as follows.


So ** We were able to achieve morphological analysis with the minimum configuration of GAE! ** **

This time, I decided to use igo-python without considering the accuracy. If you want natural language processing & accuracy within LineBot Proposal (1) Set up your own HTTPS server and install it yourself Proposal (2) Use COTOHA if you want to do it on GAE or Heroku. Etc. seems to be the correct way to proceed.

Also, for the implementation that runs Word2Vec / Gensim equivalent without a server, I'm in the middle of the road so I'll see you off. Someday on another occasion. (Up to the point of moving simple things, it is realized in a surprising way. Since the model file itself is heavy, the balance with accuracy is ... )

3-2. The story when it works locally but not on GAE

Now, like the above-mentioned experiment of incorporating natural language processing, If processing fails due to GAE memory dependence

** It works during local development, but ** ** Does not work when uploaded to the server **

There are many cases.

Also, LineBot requires an HTTPS server, which also It is difficult to test in a local development environment, so In the vicinity of the lineMessagingAPI-GoogleStaticMapsAPI linkage, ** Processing that can be confirmed only after deploying to GAE ** occurred frequently.

In these cases, if you send a chat to AYANO, ** Ignore read **, will be repeated. If you read and ignore it every time you deploy, it will be ** heartbreaking **.

I haven't found a very good solution for this.

For the time being, as a slightly better method, (1) The standard output log such as print is Since you can see them collectively with "Logging (Stackdriver)" in GCP, Write a print in a suitable place when debugging (2) To be able to separate Line-related problems from other problems From GET access to the server without going through Line Make it so that you can hit the created function Is it two points?

Below are the main processes of Flask-LineBot. Comments are added with ★ in the places corresponding to ①②.


#Line's WebHook is POST type and is not used for normal GET URL access
#The following is for checking the communication of the server
#★ In this way, create a place where you can check other than Line's WebHook,
#If you call the function you want to check in these places,
#It is possible to isolate problems with Line related problems.
@app.route("/", methods=['GET'])
def sayhello_root():
    """Return a friendly HTTP greeting."""
    return '[200] It works!'

#Set to Line's WebHook and receive + reply to messages
#If you want to send a message with a bot, on Line's Developer console,
#A message will be sent by POST to the URL described in "Webhook URL * SSL only supported".
#Reference: https://www.casleyconsulting.co.jp/blog/engineer/3028/
@app.route("/", methods=['POST'])
def callback():
    #Get the value for signature verification from the request header
    signature = request.headers['X-Line-Signature']
    #Get request body
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    #Verify the signature, and if there is no problem, call the function defined in handle.
        handler.handle(body, signature)
    #If signature verification fails, raise an exception.
    except InvalidSignatureError:
    return 'OK'

#The following is the handle definition
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    #Special code to make "connection confirmation" of Line OK
    #When you press "Check Connection" on Line's Developer Console
    #If you make it normally, reply_500 returns due to illegal token.
    #I get angry if the expected 200 is not returned on the connection confirmation side.
    #Problems on Line's console as of November 2019. Probably will be resolved eventually.
    #Reference: https://qiita.com/q_masa/items/c9db3e8396fb62cc64ed
    if event.reply_token == "00000000000000000000000000000000":
    #Get the message in the event
    input_text = event.message.text
    #★ Standard output is aggregated and displayed in "Logging" in GCP, so
    #It is easy to debug if you print out at key points.
    #Parse the message and create "line messages" for reply
    #★ Without writing all the processing in the webhook or handler
    #The main process is created by an external function,
    #Without going through a webhook or handler
    #Make it so that you can call and confirm directly
    reply_messages = makeLineMessages(input_text)

    #reply_message is free in principle,
    #reply_The token has a valid period and cannot be processed for a very long time.
    #The following is the basic form:
    #    event.reply_token,
    #    [
    #        TextSendMessage(text= reply_text),
    #    ]

    #Reply and finish.

#Flask on GAE (python3).Sample to move in 7):
#「gae_python37_Created based on "app"
if __name__ == '__main__':
    # This is used when running locally only. When deploying to Google App
    # Engine, a webserver process such as Gunicorn will serve the app. This
    # can be configured by adding an `entrypoint` to app.yaml.
    app.run(host='', port=8080, debug=True)

This concludes the technical topic.

** Postscript (Poem) **

Background of AYANO LineBot Bomb

In the past days, I had the opportunity to visit Line because of a certain activity (outside business). It was a very enjoyable time for us to respond / introduce us very kindly. We would like to take this opportunity to thank you again.

At that time, he also answered in detail the technical QA about LineBot. This article is a comprehensive article of the knowledge / know-how gained from the QA. (Because it was said that you can write it on Qiita etc. ~~ (rather recommended to write) ~~) ** LineBot development for the first time! At that time, I intend to summarize the points that I am very worried about **.

But the result of QA is "I'm sorry, I can't go to the classmate bot" You wouldn't have thought at all! ~~ I'm really sorry. ~~

Impressions of creating LineBot

I touched both LineBot and GAE for the first time.

When creating a LineBot, explain "Why you have to reply with Line (bot)" How do you design it? I feel that is the biggest point. LIFF (LINE Front-end Framework) Although there is a function to embed a web application in Line, It is not possible to realize the application with Line, but it is essential to realize it within Line. It should be designed. The simplest way to achieve that design is with a "** character **". This time, in order to increase the presence of AYANO, it was essential to realize it on Line.

There are many pages that explain how to make a LineBot, but this one ** Why should I make it as a LineBot? How to design a bot? ** is I have the impression that it is not often talked about.

For example, another possibility is "** Group chat or dialogue with friends **". If you want to make an "Othello (Reversi) app", With web apps and smartphone apps, it seems a little difficult to implement battles between friends. The same applies to schedule sharing apps. By implementing it on Line / LIFF, if you call a bot for group chat, It seems that such a problem can be solved. If you want to create a match against AI or a matching match against strangers Create with a web app or smartphone app, and on Line for the purpose of playing against friends, It is better to think about the design first. Another policy is to create a bot for the purpose of supporting human intervention as appropriate.

Considering the ** "characteristics" ** of LineBot, I think it's easy to come up with the next idea! !!

Impressions of GAE usage / natural language processing

GAE (serverless) handles natural language processing To be honest, it was harder than I expected. Natural language processing originally requires "dictionary" and "word-by-word data", so The problem is that it is "heavy" no matter where it is implemented.

For example, in the article below, take the plunge I have also tried implementing it on the front end (JavaScript / PWA) side. https://qiita.com/youwht/items/6c7712bfc7fd088223a2

The processing became the fastest when it was moved to the front side, Because the morphological analysis library is included in the package The distribution file size at the first startup is a little heavy I felt it as an issue. (The accuracy is not good enough)

Even in GAE (serverless), depending on the weight, Decent accuracy x processing content is not assembled.

GAE itself is when making light processing No infrastructure required, just Python code to become an HTTPS server, It's pretty convenient. However, there is still a habit, I don't feel like I can do anything that Python can do, You will need to be careful when using it.

This time, although natural language processing is heavy, Up to this level, you can do it with GAE (serverless), right? I think it was good to get the feeling!

Next, should I make it with COTOHA API?

Work that leaves no friends

** "I'm in Singapore now." ** ** If you decline any invitation ** ** Line My only friend is AYANO. ** **

** Actually, I know AYANO is a bot, but ** ** But now I pretend I don't know a little more. ** **

** The fucking app I make is also ** ** I'm sure someday heal someone's loneliness **

That's it from Singapore.

Recommended Posts

Now in Singapore The story of creating a LineBot and wanting to do a memorable job
The story of creating a "spirit and time chat room" exclusively for engineers in the company
The story of creating a store search BOT (AI LINE BOT) for Go To EAT in Chiba Prefecture (1)
A story about creating a program that will increase the number of Instagram followers from 0 to 700 in a week
How to count the number of elements in Django and output to a template
The story of creating Botonyan that returns the contents of Google Docs in response to a specific keyword on Slack
The story of creating a store search BOT (AI LINE BOT) for Go To EAT in Chiba Prefecture (2) [Overview]
To do the equivalent of Ruby's ObjectSpace._id2ref in Python
The story of wanting to buy Ring Fit Adventure
The story of Airflow's webserver and DAG, which takes a long time to load
A story of trial and error trying to create a dynamic user group in Slack
A story about trying to introduce Linter in the middle of a Python (Flask) project
The story of creating a VIP channel for in-house chatwork
[Golang] Command to check the supported GOOS and GOARCH in a list (Check the supported platforms of the build)
Make a note of what you want to do in the future with Raspberry Pi
The story of creating a database using the Google Analytics API
A story about porting the code of "Try and understand how Linux works" to Rust
[Python] The role of the asterisk in front of the variable. Divide the input value and assign it to a variable
The story of returning to the front line for the first time in 5 years and refactoring Python Django
The story of creating a bot that displays active members in a specific channel of slack with python
How to determine the existence of a selenium element in Python
A story that struggled to handle the Python package of PocketSphinx
How to check the memory size of a variable in Python
How to check the memory size of a dictionary in Python
The story of creating a site that lists the release dates of books
How to get the vertex coordinates of a feature in ArcPy
Create a function to get the contents of the database in Go
The story of Python and the story of NaN
The story of participating in AtCoder
The story of the "hole" in the file
The story of writing a program
A story about what to do when a bad interpreter: Not such file or directory appears in Anaconda3 and how to investigate the cause.
[Rails 6] Embed Google Map in the app and add a marker to the entered address. [Confirmation of details]
[Python / Jupyter] Translate the comment of the program copied to the clipboard and insert it in a new cell
A story about trying to improve the testing process of a system written in C language for 20 years
How to copy and paste the contents of a sheet in Google Spreadsheet in JSON format (using Google Colab)
The story of a Parking Sensor in 10 minutes with GrovePi + Starter Kit
[Linux] Command to get a list of commands executed in the past
I want to sort a list in the order of other lists
I tried to extract and illustrate the stage of the story using COTOHA
The story of making a sound camera with Touch Designer and ReSpeaker
I made a program to check the size of a file in Python
I tried to display the altitude value of DTM in a graph
The story of trying to reconnect the client
The story of an error in PyOCR
The story of adding MeCab to ubuntu 16.04
How to save the feature point information of an image in a file and use it for matching
The story of trying deep3d and losing
The story of blackjack A processing (python)
The story of pep8 changing to pycodestyle
Function to extract the maximum and minimum values ​​in a slice with Go
Various ways to read the last line of a csv file in Python
How to pass the execution result of a shell command in a list in Python
Feel free to write a test with nose (in the case of + gevent)
How to mention a user group in slack notification, how to check the id of the user group
Set the number of elements in a NumPy one-dimensional array to a power of 2 (0 padded)
The story of creating (probably) the smallest skill that implements personalization and in-skill billing
The story of IPv6 address that I want to keep at a minimum
The story of making a box that interconnects Pepper's AL Memory and MQTT
To output a value even in the middle of a cell with Jupyter Notebook
Use libsixel to output Sixel in Python and output a Matplotlib graph to the terminal.