GBFSアドベントカレンダー2023の5日目です。
みなさん、ChatGPT使ってますか?
いやー、昨年の発表以来、大盛り上がりですね。Qiitaの人気記事にも毎週なにかしらのChatGPT関連の記事がランクインしているように思います。
折しもChatGPTを自分でカスタマイズして特化させる機能がOpenAIから発表されましたね。GPTs。
今回はGBFSとこれを絡めていきたいと思います。
前提
まず今回の記事の前提です。
- ChatGPT4(2023/11/17時点のモデル)
- ChatGPT Plus(or Enterprise)
本記事では、OpenStreet株式会社(ハローサイクリング) / 公共交通オープンデータ協議会のバイクシェア関連情報(GBFS形式)をCC-BY4.0に従って利用しています。
https://ckan.odpt.org/dataset/c_bikeshare_gbfs-openstreet
GBFSとはなんぞや
この記事を読むような方はそもそもGBFSをご存知かと思うのですが…
ChatGPTから流れてくる方もいらっしゃると思うので、説明記事をご紹介します!!(他力本願)
@kumatiraさんが素晴らしい記事を書いてくださっているので、私のGBFS関連の記事の始まりは全てこの記事の紹介です。
GPTsとは
ChatGPTについては万巻の書があるので説明を省きますが、GPTsについては少し補足です。
ChatGPTの開発元であるOpenAIが2023/11/6に公開した、ChatGPTの新機能です。
機能的には RAG(Retrieval Augmented Generation) です。
単なる対話AIでしかないChatGPTに、ウェブ検索などのさまざまな機能を(その呼び出しの判断ごと)追加するもので、Langchainを使って実現できるものと同様のことができます。
ただそれをChatGPTと対話しながら作れたり、ノーコードでウィザード式に作れるのが特徴です。
詳しくは公式ページを。
今回は、GBFSのデータが取れるAPIをGPTsに組み込み、ChatGPTでGBFSを操作できるようにします。
GPTsの作り方(基本設定)
まず、GPTsの作り方の簡単な説明をしつつ、今回のGPTsの設定をしていきます。
なお、前提にあるとおり、GPTsはPlusかEnterpriseユーザー限定です。無償ユーザーの方は、フーンと思いながら読んでください。
またChatGPTはしばしばUIが変わります。この記事は2023/11月時点のUIで説明をしています。
今後、UIが変更されたら読み替えてください。
ChatGPTのトップ画面から説明していきます。
- ChatGPT画面右上の「Explore」を選択
- 「Create a GPT」を選択
そうすると次のような画面になります。
画面左側がGPTsの設定画面、右側がプレビュー画面です。
初期では「Create」になっていて、ChatGPTと対話しながらGPTsを作れる画面になっています。
「Configure」を選ぶと、次の画面になります。
私はこちらの方が好きなので、こちらをメインに説明していきます。
項目 | 説明 | 今回の設定例 |
---|---|---|
⚪︎に+のところ | アイコンの設定です。アイコン画像を用意しなくてもDALL-Eで生成できます。 | DALL-Eを使って作ってもらいました。ださい。 |
Name | このGPTsの名前です。 | 「OpenStreetGBFS」 |
Description | このGPTsの説明です。 | 「OpenStreetが公開するGBFSのstation_informationを操作します」 |
Instruction | このGPTsになにをさせたいか、役割や、口調、予備知識などを与えます。 | 「あなたはOpenStreetのエンジニアです。GBFSのstation_information APIを使い、指示された情報を示したり、コードを実装、実行してください」 |
Conversation starters | ユーザープロンプトの例示の設定です。このGPTsをどう使っていいかの例を示すなど、まずユーザーに試してほしいことなどを記述します。 | 今回は設定しません |
Knowledge | データソースになるファイルを指定できます。指定できるファイルは決まっているようですが、PDF、CSVなどが指定できます。文章ファイルの場合、ベクトル化されてChatGPTが参照できるようです。 | 今回は使いません。 |
Capabilities | このGPTsで使う拡張機能です。 | Web Browsing: OFF DALL-E Image Generation: OFF Code Interpreter: ON |
Actions | このGPTsで使用するAPIを指定できます。 | 後述するGBFSのAPIエンドポイントを指定します。 |
さて、Actionsに指定するGBFSのAPIエンドポイントの設定については次章に譲ります。
まずそれ以外の項目を埋めます。埋めたのがこちら。
Actions
では、ActionsにGBFSのAPIを設定していきましょう。
Actionsの「Create new action」を選択します。
すると次のAPIの設定画面になります。
Schemaのプレースホルダーに書いてあるとおり、OpenAPI形式で指定ができます。
また「Import from URL」や「Examples」には、既存のAPI定義を取り込んだり、テンプレを指定できます。
今回は、OpenStreetがODPTで公開しているGBFSの定義を作っていきます。
フルスクラッチで定義を書いてもいいのですが、今回、これもChatGPTに作ってもらいましょう。
ここは面倒なので、作った過程を共有します。
できたYAML形式の定義がこちらなのですが、3点誤りがあるため直します。
貼り付けた定義は修正後のものです。
- servers:urlで、最後のスラッシュが不要。urlにスラッシュがついていると、呼び出し時、hellocycling//station_information.jsonとなり、404になります
- operationIdの追加。不要かと思いましたがこれ必須でした
- GBFSの共通レスポンスでlast_updatedとversionを指示し忘れてたのを修正
openapi: 3.0.0
info:
title: GBFS Of OpenStreet Bikeshare Service
description: This is a GBFS API Server of OpenStreet.
version: 1.0.0
servers:
- url: https://api-public.odpt.org/api/v4/gbfs/hellocycling
description: Product API end point
paths:
/station_information.json:
get:
summary: List all station information. id, position, vehicle capacity and soon.
operationId: List stations
responses:
'200':
description: A list of station information including location, name, and vehicle capacity.
content:
application/json:
schema:
type: object
properties:
ttl:
type: integer
last_updated:
type: integer
version:
type: string
data:
type: object
properties:
stations:
type: array
items:
$ref: '#/components/schemas/Station'
components:
schemas:
Station:
type: object
properties:
lat:
type: number
format: float
description: Latitude of the station.
lon:
type: number
format: float
description: Longitude of the station.
name:
type: string
description: Name of the station.
address:
type: string
description: Address of the station.
station_id:
type: string
description: Unique identifier of the station.
rental_uris:
type: object
properties:
ios:
type: string
description: Station URL for iOS devices.
web:
type: string
description: Station URL for PC web browsers.
android:
type: string
description: Station URL for Android devices.
parking_hoop:
type: boolean
description: Are parking hoops present at this station?
parking_type:
type: string
description: Type of parking. Values are "parking_lot", "street_parking", "underground_parking", "sidewalk_parking", and "other".
contact_phone:
type: string
description: Contact phone number for the station.
is_charging_station:
type: boolean
description: Does the station support charging of electric vehicles?
vehicle_type_capacity:
type: object
properties:
num_bikes_now:
type: integer
description: Current number of bikes at the station.
num_bikes_limit:
type: integer
description: Maximum number of bikes the station can hold.
num_bikes_parkable:
type: integer
description: Current number of bikes the station can park.
num_bikes_rentable:
type: integer
description: Current number of bikes the station can rent.
さて、この定義をSchemaに貼り付けます。
ODPTのこのAPIは認証がないので、Authenticationは「None」のままでいいです。Privacy Policyも特に指定がないので空にします。
貼り付けると、このように利用可能なアクションが表示され、テスト可能になります。
「Test」をすると実際にAPIが実行され、プレビュー画面でデバッグできます。
はい、ダメでした…
要するに「レスポンスとは受け取れたけどデカすぎて使えないよ」ということです…
APIを絞る
仕方ないのでAPIを絞ります。
ここはこの記事の本題ではないので、やったことだけ説明します。
- python flaskでsystem_information.jsonを「東京都小平市」に絞るAPIを実装
- 同APIをローカルホストで実行
- VisualStudioCodeのポートフォワーディングでローカルホストのAPIを外部実行可能なURLを発行
- APIを認証が不要な「公開」に設定
- GPTsのActionsのSchemaに指定したOpenAPIのserversを発行されたURLに変更
これで無事、APIが動作しました。
大したソースではありませんが、1.のソースは一応示しておきます。
(このソースも半ばGithub Copilotに書かせています)
import requests
import json
import flask
app = flask.Flask(__name__)
@app.route('/station_information.json')
def station_information():
url = "https://api-public.odpt.org/api/v4/gbfs/hellocycling/station_information.json"
res = requests.get(url)
station_information = json.loads(res.text)
_d = {}
_d["last_updated"] = station_information["last_updated"]
_d["ttl"] = station_information["ttl"]
_d["version"] = station_information["version"]
_d["data"] = {}
_d["data"]["stations"] = []
for station in station_information["data"]["stations"]:
if "東京都小平市" in station["address"]:
_d["data"]["stations"].append(station)
return flask.jsonify(_d)
if __name__ == '__main__':
app.run()
動かしてみる
動かしてみた結果がこちらです。
コードを示してくれと言ったけど、結果を示しているところはありますが…、全般的にはだいぶいいですね!
GBFSはJSON仕様としては、比較的シンプルなものの、非エンジニア職にはやはり扱いにくいものですし、エンジニア職でも解析しようとしたらコードを書かねばなりません。
GPTsにしておくことで、その操作がパッとできるのはちょっとしたやりたいこと、知りたいことをパッと形にしてくれます。
APIやドキュメントと組み合わせることで、会社やオープンデータとしてある資産を生かす道が広がるのではないでしょうか。
と言ったところで、今回の記事を終わりたいと思います。