🎃

ChatGPTで防災情報を管理してみる

2024/01/22に公開

レスキューナウでデータ管理を行なっているエンジニアの坂本です。

現代社会において、正確かつ迅速な情報収集は非常に重要です。
特に災害時におけるライフライン情報、例えば停電情報は、多くの人々にとって必要不可欠なものです。
このブログでは、レスキューナウのサービスとして提供している停電情報のXMLデータとChatGPTのAPIを組み合わせて一般的には出回っていない市区町村以下の町域で抽出し、これをChatGPTのAPIと組み合わせて自然言語処理により分析します。
Pythonを用いて、得られたデータをJSON形式に整形し、これを変数として管理します。
ここで生成されるJSONデータは、後に任意のデータベースに登録するための基盤として機能します。

このプロセスは、XMLデータの解析から始まり、ChatGPTの自然言語処理機能を活用してデータを解釈し、最終的にはデータベースに情報を整理して保存するという流れになります。これにより、停電情報の迅速な収集と効率的な管理が可能になります。
データベースへの登録は本ブログの範囲外となりますが、生成されたJSONデータは様々なデータベースシステムで利用可能です。

目次

  • xml構成確認
  • プログラムからjson作成
  • まとめ

XML構成確認

sample
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<product>
  <dataconf>
    <conf>data</conf>
  </dataconf>
  <prodIdInfo>
    <infoId>00000014356780</infoId>
    <category0>0005</category0>
    <name0>緊急</name0>
    <category1>00050002</category1>
    <name1>ライフライン情報</name1>
    <category2>000500020001</category2>
    <name2>電気情報</name2>
    <publishTime>2023-12-19T07:00:00+09:00</publishTime>
    <followupNum>00000014392981</followupNum>
    <limitTime/>
    <levelInfo>3</levelInfo>
    <areaKbn>01</areaKbn>
    <levelEarea/>
    <upDelFg>N</upDelFg>
  </prodIdInfo>
  <body>
    <title>浜松市天竜区の一部地域で停電(12/19)</title>
    <text1>中部電力パワーグリッドの発表によると、6日17:02頃、静岡県浜松市天竜区の一部地域で停電が発生しました。現在、復旧作業が行われています。</text1>
    <text2>中部電力パワーグリッドの発表によると、6日17:02頃、静岡県浜松市天竜区の一部地域で停電が発生しました。現在、復旧作業が行われています。&#13;
&#13;
■影響地域&#13;
浜松市天竜区:約100軒(天竜川三丁目、天竜川五丁目)&#13;
※軒数は近隣営業所との合算の可能性があります。</text2>
    <area>
      <levelInfo>3</levelInfo>
      <p0>
        <code>1</code>
        <name>日本</name>
      </p0>
      <p1>
        <code>22</code>
        <name>静岡県</name>
      </p1>
      <p2>
        <code>22137</code>
        <name/>
      </p2>
      <p3>
        <code>0</code>
        <name/>
      </p3>
      <p4>
        <code>0</code>
        <name/>
      </p4>
      <p5>
        <code>0</code>
        <name/>
      </p5>
      <note/>
    </area>
  </body>
  <attribute>
    <common/>
    <detailAll>
      <company>中部電力パワーグリッド</company>
      <occurrenceTime>2023-12-06T17:02:00+09:00</occurrenceTime>
      <occurrenceTime_flag>01</occurrenceTime_flag>
      <estimatedTime/>
      <estimatedTime_flag>03</estimatedTime_flag>
      <restorationTime/>
      <restorationTime_flag>03</restorationTime_flag>
      <house>
        <num>100</num>
        <flag>01</flag>
      </house>
      <cause/>
      <areaText>天竜川三丁目、天竜川五丁目</areaText>
    </detailAll>
  </attribute>
</product>

上記の情報では天竜川三丁目、天竜川五丁目で合わせて100件ほどの停電が発生していることが確認できます。
しかし町域については文字列として発表しているため、自然言語解析が必要になります。

サンプルプログラムでJSONを出力

xmlファイルを参照し、ChatGPT APIにインポートした結果をコンソールに出力していきます。

main
import os
# OpenAIライブラリからOpenAIクラスをインポート
from openai import OpenAI

os.environ["OPENAI_API_KEY"] = "API-KEY"

# OpenAIクライアントを初期化
client = OpenAI()

with open("sample.xml", "r") as file:
    sample = file.read()

# GPT-4モデルを使用してチャット応答を生成
stream = client.chat.completions.create(
    model="gpt-4-1106-preview",  # 使用するモデルを指定(ここではgpt-4-1106-preview)
    messages=[{"role": "system", "content": '\
               Please convert the blackout information described in the provided XML file into a JSON format like {city/ward/town/village{neighborhood:name of event},...}. \
               Do not respond in any format other than JSON.\
               Example:{"中央区"{"明石町":"停電","月島":"停電"},"練馬区":{"氷川台":"停電"}} \
               For Japanese designated cities, please describe the city and its wards under the item "municipalities".'},
              {"role": "user", "content": sample }
              ],
    stream=True,  # 応答をストリームとして受け取る
)

# ストリームから受け取ったデータを処理

for chunk in stream:
    # 応答のテキスト部分(content)がNoneでなければ出力
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end="")

今回指定しているプロンプトは以下のようになります。

Please convert the blackout information described in the provided XML file into a JSON format like {city/ward/town/village{neighborhood:name of event},...}.
Do not respond in any format other than JSON.
Example:{"中央区"{"明石町":"停電","月島":"停電"},"練馬区":{"氷川台":"停電"}}
For Japanese designated cities, please describe the city and its wards under the item "municipalities

日本語訳
提供されたXMLファイルに記述された停電情報を、JSON形式で次のように変換します。
「市/区/町/村{地域:イベント名}」の形式です。
JSON形式以外の形式での回答は行いません。
例:{"中央区":{"明石町":"停電","月島":"停電"},"練馬区":{"氷川台":"停電"}}。
政令指定都市の場合は、"市"とその区を"municipalities"項目の下に記述してください。

プロンプトは至る所で日々研究がされているので、もっと良いプロンプトがあるかもしれません。

JSON出力結果

以下のようなjsonとして管理してもらえました。

{
  "浜松市天竜区": {
    "天竜川三丁目": "停電",
    "天竜川五丁目": "停電"
  }
}

jsonで出したデータをPタグに入れてみる

# ストリームから受け取ったデータを処理
response_text = ""
for chunk in stream:
    # 応答のテキスト部分(content)がNoneでなければ出力
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end="")
        response_text += chunk.choices[0].delta.content

data = json.loads(response_text)

prefecture = list(data.keys())[0]
municipalitie = list(data[prefecture].keys())[0]
print(municipalitie)
# XMLファイルをパースする
tree = ET.parse('sample.xml')

# ルート要素を取得する
root = tree.getroot()

# 'p2'要素の'name'タグを見つけてテキストを設定する
for p2 in root.iter('p2'):
    name = p3.find('name')
    if name is not None and name.text is None:
        # jsonの市区町名を入力する
        name.text = municipalitie
tree.write('output.xml',encoding='utf-8')

上記の処理でoutput.xmlという新しいxmlを出力します。

出力結果

町域はXMLの仕様と違うためP3のタグは入れていませんが、文字列からデータを解体してPタグを拡張することができました。

 <area>
      <levelInfo>3</levelInfo>
      <p0>
        <code>1</code>
        <name>日本</name>
      </p0>
      <p1>
        <code>22</code>
        <name>静岡県</name>
      </p1>
      <p2>
        <code>22137</code>
        <name>浜松市天竜区</name>
      </p2>

まとめ

今回はxmlデータでの解析となりましたが、これはテキストベースであれば全てのファイルに対応していると考えて良さそうです。
かなりシンプルな構成となりますが、データクレンジング系の業務では今後活躍していくことが期待されます。

レスキューナウテックブログ

Discussion