9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【ChatGPT API × ラズパイ × LINEbot】ChatGPT君、きょう何着て行く?

Posted at

春の服選びはめんどくさい

コートを着て行くと暑くなり、パーカーで出かけると寒くなる。かと思えば半袖が必要なくらい暑い日もある。

困りませんか?困りますよね。

そんなときは!

みんな大好きChatGPT君にLINEして何を着ればいいか教えてもらいましょう:robot:

事前準備

以下の準備は先人たちの知恵をお借りして、各自準備をお願いします。
書いてある通りにやれば動く、とってもわかりやすい記事を集めました。

OpenAIのアカウント作成もお忘れなく。

ChatGPT APIの料金体系について知ろう

ブラウザでChatGPTを使うのは無料(注:課金バージョンも有り)ですが、APIは基本的に有料です。高額請求が来るのが怖かったので、先人の知恵をお借りし、料金体系について勉強しました!

ふむふむ…

ChatGPTのAPIはトークンという単位で課金されるのですね。
記事によると、トークン量を減らして利用料金を抑えるためには以下のことに気を付ければいいようです。

  • APIに含めるやり取りは直前n回までと設定する
  • max_tokensの上限を設定する
  • 英語でやり取りする

また高額請求を避けるため、APIの利用上限を設定することも必要そうです。

機能設計

当初はこんなアプリを作ろうと考えていました。
IMG_7271.jpg

まずはChatGPT君が期待する質問に答えてくれるか確認するため、ブラウザ版を利用したテストを行いました。
image.png
むむむ…!?

なんか、思ってたのと違う:neutral_face:

何度やってもChatGPT君は、最高気温と最低気温それぞれに合わせたコーディネートを1つずつ提案してくる:neutral_face:

ということで初期構想の機能は一旦あきらめ、
わたし:「今日の気温は15度」
ChatGPT:「パーカーに長袖長ズボンを着ましょう」
くらいの単純な機能から実装することにしました!

コーディング

以下のコードを作成しました。

app.py
from flask import Flask, request, abort
#解説1
from translate import Translator
import json
from linebot import (
   LineBotApi, WebhookHandler
)
from linebot.exceptions import (
   InvalidSignatureError
)
from linebot.models import (
   MessageEvent, TextMessage, TextSendMessage,
)
import openai
import os

# ご自身で取得したキーを入力
line_bot_api = LineBotApi('Channel access token')
handler = WebhookHandler('Channel secret')
openai.api_key = 'Openai apikey'

# 解説2
def chat_chatgpt(lineRes) :
    chatgpt_res = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {
                "role": "user",
                "content": 'Suggest one of best outfits in ' + str(lineRes) + 'C with 10words limit'
            }
        ]
    )
    res_eng = chatgpt_res["choices"][0]["message"]["content"]
    translator = Translator(from_lang='en', to_lang='ja')
    res = translator.translate(res_eng)
    return res


app = Flask(__name__)

@app.route("/callback", methods=['POST'])
def callback():
   # get X-Line-Signature header value
   signature = request.headers['X-Line-Signature']
   
   # get request body as text
   body = request.get_data(as_text=True)
   app.logger.info("Request body: " + body)
   
   # handle webhook body
   try:
       handler.handle(body, signature)
   except InvalidSignatureError:
       print("Invalid signature. Please check your channel access token/channel secret.")
       abort(400)
   return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
   lineRes = event.message.text
   botRes = 'ピピピ…今日ノ気温ヲ入力シテクダサイ…'
   
   # 解説3
   if lineRes.isdecimal():
        botRes = chat_chatgpt(lineRes)

   line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=botRes))


if __name__ == "__main__":
   app.run()

解説1

ChatGPTは英語でやり取りするとトークン量を減らすことができますが、このサービスのユーザは日本語話者が多いと想定しています。
そこで、PythonのTranslatorライブラリを利用し、ユーザがLINE上でChatGPT君と日本語でやり取りできるようにしました。

解説2

ChatGPT君に話しかけるための関数です。ユーザの入力値(数値)を受け取り、ChatGPTにリクエストを投げます。

Suggest one of best outfits in ' + str(lineRes) + 'C with 10words limitを和訳すると、「10語以内でおすすめのコーディネートを1つ提案してください」になります。10語以内縛りにした理由はこちらです👇
image.png
ChatGPT君によると、10語を超えるかどうかでトークン使用量が2変わるようなので、無理やりリクエスト・レスポンスともに10語以下になるように設定しました(ドケチ)
ほんとにChatGPT君はなんでも教えてくれますね。

解説3

ユーザとLINEでやり取りするための関数です。
ユーザの入力値が数値の場合ChatGPTとやり取りするための関数chat_chatgptを呼び出します。数値以外の場合はデフォルトで設定した返答をユーザに返します。

コードの解説は以上となります。

動作確認

動くかわかんないけど、とりあえず実行!!
LINEで話しかけてみた!

image.png

・・・・・・使えちゃった:neutral_face:

あれ、でもさっき調べたトークンやAPIの上限値設定とかしてないんだけど…?
そもそもクレカも何も登録してないんだけど…???
支払いどうなってるのーーーー!?!?!?:scream:

ChatGPT APIの支払いどうなってるの?

ということで調べました。
おそるおそる検索してみると、支払いの設定などができるサイトがあるとの情報を入手!

  • サイト:https://platform.openai.com/
    Personal⇒Manage Account⇒UasgeでAPIの使用量が確認できます!
    image.png
    わ!ちゃんと使ったことになってる!!
    0.00025ドルなら大丈夫だ、払える:joy:
    (というかこのページAPIkey発行で使ったな・・・)

image.png
あれ?Free trial Usage…?18ドル分…!?!?

これについても調べました。

ChatGPTのAPIには初回3か月の無料トライアル使用枠があるようです。
私がOpenAIのアカウントを作成したのはたしか2月頃なので、5/1で3か月ということなのでしょう。ただし、現在は無料使用枠は5ドル/3か月に減ってしまっているようです。

無料使用枠が終了してもAPIが使えなくなるだけで、勝手に課金されることはないようです。よかった:sweat_smile:

ちなみにAPI使用量の上限はBilling⇒Usage limitsで設定できますが、無料使用枠を使っている間は設定ができないようです。

ちなみにちなみに、以下の設定方法はChatGPT君が教えてくれましたが、今回はめんどくさいのでやり取りの文字数制限をしていることもあり、実装はしません。

  • APIに含めるやり取りは直前n回までと設定する
  • max_tokensの上限を設定する
    image.png
made_by_chatgpt.py
import openai
openai.api_key = "YOUR_API_KEY"

prompt = "Hello, how are you doing today?"
model = "text-davinci-002"
max_tokens = 50
temperature = 0.5
max_history = 2

response = openai.Completion.create(
    engine=model,
    prompt=prompt,
    max_tokens=max_tokens,
    temperature=temperature,
    max_history=max_history
)

print(response.choices[0].text)

機能追加

ユーザが気温を入力するのは少しイケてないですよね。。。
そこで、ユーザが質問すればお天気APIから今日の気温を取得して服装を提案する機能を追加してみました!

app.py
from flask import Flask, request, abort
from translate import Translator
import json
from linebot import (
   LineBotApi, WebhookHandler
)
from linebot.exceptions import (
   InvalidSignatureError
)
from linebot.models import (
   MessageEvent, TextMessage, TextSendMessage,
)
import openai
import os

# ご自身で取得したキーを入力
line_bot_api = LineBotApi('Channel access token')
handler = WebhookHandler('Channel secret')
openai.api_key = 'Openai apikey'

# added
import requests
weatherAPI='https://api.openweathermap.org/data/2.5/weather'
params={
    # ご自身で取得したキーを入力
    "appid": "OpenWeatherAPIkey",
    "q": "TOKYO",
    "units": "metric",
    "lang": "ja"
}

def get_temperature():
    weather = requests.get(weatherAPI, params=params).json()
    temp = weather["main"]["temp"]
    return temp
# added

# modified
def chat_chatgpt() :
    temp = get_temperature()
    chatgpt_res = openai.ChatCompletion.create(
       model="gpt-3.5-turbo",
       messages=[
           {
               "role": "user",
               "content": 'Suggest one of best outfits in ' + str(temp) + 'C with 10words limit'
           }
       ]
   )
    res_eng = chatgpt_res["choices"][0]["message"]["content"]
    translator = Translator(from_lang='en', to_lang='ja')
    res = translator.translate(res_eng)
    return res
# modified

app = Flask(__name__)

@app.route("/callback", methods=['POST'])
def callback():
   # get X-Line-Signature header value
   signature = request.headers['X-Line-Signature']
   
   # get request body as text
   body = request.get_data(as_text=True)
   app.logger.info("Request body: " + body)
   
   # handle webhook body
   try:
       handler.handle(body, signature)
   except InvalidSignatureError:
       print("Invalid signature. Please check your channel access token/channel secret.")
       abort(400)
   return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
   lineRes = event.message.text
   botRes = 'ピピピ…服装ヲ提案シマス…'
   
   # modified
   if '何着' in lineRes:
       botRes = chat_chatgpt()
   # modified
   
   line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=botRes))


if __name__ == "__main__":
   app.run()

詳しい説明は省きますが、addedとmidifiedで挟まれているところが最初のコードとの差分になります!

完成!

image.png

・・・クロップトップ?コンバットブーツ?

クロップトップ、調べてみたら露出が多くて今日の気温(18度くらい)だと寒そうです:joy:
とにもかくにも、ChatGPT君からLINEで服装のアドバイスをもらえるようになりました:raised_hands:

参考にしたサイト

たくさんの先人の知恵をお借りしました。感謝申し上げます。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?