⚙️

旅行アプリ開発記録② 技術構成の概要

に公開

概要

このアプリは、ユーザーが簡単な条件を入力するだけで、数時間から丸一日までの旅行計画を自動生成するシステムです。一応特徴にしているのは、「今すぐ」なので、細かい設定はあえてできないようにしました。概要はこちらで記事にします。

構成は大きく2段階に分かれていて、まず「旅行先の候補エリアの提示」、その後に「詳細な観光プランの提示」を行います。

ユーザー入力項目

今すぐ出かけることをメインにしているので、mustの入力は最小限にしています。

  • 現在地点・・・flutter側でgeocodingして位置情報に変換
  • 現在時刻
  • 旅行時間(0.1〜24時間)
  • 食事を含むかどうか
  • 移動手段(徒歩、電車、車)

以下はオプションの選択肢

  • 気分(リラックス、アクティブ等)
  • ペース(ゆっくり、普通、早い等)
  • 新しさ(定番、ふつう、穴場等)
  • カスタマイズ要望(自由記述、500文字以内)

第1段階:search_plan

エリア候補生成 を行う処理を1つのエンドポイントとしてfastAPIをバックエンドメインとして作成しています。

  • 住所変換
    Google Geocoding APIで、入力された緯度経度から住所を取得。
  • エリア候補生成
    OpenAI GPT-4.1 nanoを1回呼び出し、候補となる旅行エリアを提案してもらいます。プロンプトにはユーザー位置、旅行時間、ユーザーのオプション情報等を混ぜていれてるのと、提案エリアを魅力的にPRする文章も出して、と入れてます。この辺りもLLmならではかなと。
  • 候補エリアの写真取得
    Google Photos APIで候補エリアごとの写真を取得し、視覚的なイメージを提示。約1円/枚という高額なのですが、代替もすぐには用意できないため致し方なく。。。
  • 最寄り駅検索(電車モード時)
    実はGoogle Direction APIのtransitモードで電車が選べない問題があり、、、苦戦しました。長くなるので別記事にしますが、代替案で電車経路を検索するようにしています。

    引用:GoogleMaps Document

エリア提案までのシステムシーケンスは以下

バックエンドからの応答フォーマットは以下。

{
  "status": "success",
  "areas": [
    {
      "area_name": "鎌倉・長谷エリア",
      "description": "歴史ある古都の風情を感じられる、落ち着いた雰囲気の観光地。大仏や竹林など、日本の伝統美を体験できる穴場スポットが点在しています。",
      "lat": 35.318911,
      "long": 139.536167,
      "photo_urls": [
        "https://places.googleapis.com/v1/places/photo1.jpg",
        "https://places.googleapis.com/v1/places/photo2.jpg",
        "https://places.googleapis.com/v1/places/photo3.jpg"
      ],
      "spots": []
    },
    {
      "area_name": "江ノ島・片瀬エリア", 
      "description": "湘南の海を望む開放的なリゾート地。海風を感じながらゆっくりと散策でき、夕日の美しさは格別です。",
      "lat": 35.299167,
      "long": 139.481944,
      "photo_urls": [
        "https://places.googleapis.com/v1/places/photo4.jpg",
        "https://places.googleapis.com/v1/places/photo5.jpg"
      ],
      "spots": []
    }
  ],
  "location": "神奈川県鎌倉市",
  "start_time": "2024年1月15日 14:00",
  "end_time": "2024年1月15日 18:00",
  "original_lat": 35.308056,
  "original_lng": 139.550278,
  "lat": 35.308056,
  "long": 139.550278
}

第2段階:generate_plan

こちらも 詳細プラン生成 を行う処理を1つのエンドポイントとしてfastAPIをバックエンドメインとして作成しています。

  • スポット検索
    Google Places API Text Searchで観光スポットやレストラン(食事を含む場合)を検索。
    観光地も食事も深夜など営業時間外の場合に対して多少工夫しているので別記事にしたいです。
  • 詳細情報取得
    Google Places API Detailsで営業時間や施設タイプなどを取得。最大20〜40件を並列処理にして応答性を多少確保してます。Deatail APIも高いんですよね。。。
  • プラン生成
    OpenAI GPT-4.1-nanoを1回呼び出し、取得したスポットから最適な観光プランを作成。ここでも各エリアの魅力的なPR文を出力してもらうようにしてます。
  • 位置情報と写真取得
    Google Geocoding APIでスポットの位置情報を取得し、Google Photos APIで写真を取得。例にもれず高額です。
  • 移動情報の追加
    Google Directions APIで移動時間やルート詳細を取得し、プランに反映。

バックエンドからの応答フォーマット

{
  "status": "success",
  "result": [
    {
      "name": "鎌倉大仏殿高徳院",
      "description": "鎌倉のシンボルとして親しまれる高さ11.3mの青銅製大仏。13世紀に建造された歴史ある仏像で、穏やかな表情が心に安らぎをもたらします。境内は静寂に包まれ、ゆっくりと参拝できる落ち着いた空間です。",
      "photo_urls": [
        "https://places.googleapis.com/v1/places/buddha1.jpg",
        "https://places.googleapis.com/v1/places/buddha2.jpg",
        "https://places.googleapis.com/v1/places/buddha3.jpg"
      ],
      "center_lat": 35.316667,
      "center_lng": 139.535556,
      "lat": 35.316667,
      "lng": 139.535556,
      "original_lat": 35.308056,
      "original_lng": 139.550278,
      "移動時間": "徒歩15分",
      "滞在時間": "1時間30分",
      "opening_hours": [
        "月曜日: 8:00 - 17:30",
        "火曜日: 8:00 - 17:30",
        "水曜日: 8:00 - 17:30",
        "木曜日: 8:00 - 17:30",
        "金曜日: 8:00 - 17:30",
        "土曜日: 8:00 - 17:30",
        "日曜日: 8:00 - 17:30"
      ],
      "meal": "",
      "URL": "https://www.kotoku-in.jp/"
    },
    {
      "name": "鎌倉 長谷寺",
      "description": "十一面観音菩薩が安置される古刹で、四季折々の花々が美しい庭園が自慢。特に紫陽花の名所として知られ、高台からは由比ヶ浜を一望できます。心静かに散策できる癒しのスポットです。",
      "photo_urls": [
        "https://places.googleapis.com/v1/places/hasedera1.jpg",
        "https://places.googleapis.com/v1/places/hasedera2.jpg"
      ],
      "center_lat": 35.312222,
      "center_lng": 139.533889,
      "lat": 35.312222,
      "lng": 139.533889,
      "original_lat": 35.308056,
      "original_lng": 139.550278,
      "移動時間": "徒歩8分",
      "滞在時間": "1時間",
      "opening_hours": [
        "月曜日: 8:00 - 17:00",
        "火曜日: 8:00 - 17:00",
        "水曜日: 8:00 - 17:00",
        "木曜日: 8:00 - 17:00",
        "金曜日: 8:00 - 17:00",
        "土曜日: 8:00 - 17:00",
        "日曜日: 8:00 - 17:00"
      ],
      "meal": "",
      "URL": "https://www.hasedera.jp/"
    },
    {
      "name": "鎌倉茶房 長谷店",
      "description": "長谷観音の近くにある落ち着いた雰囲気のカフェ。地元鎌倉野菜を使った軽食や、こだわりの抹茶スイーツが人気。観光の疲れを癒やす穏やかな時間を過ごせます。",
      "photo_urls": [
        "https://places.googleapis.com/v1/places/cafe1.jpg"
      ],
      "center_lat": 35.313056,
      "center_lng": 139.534167,
      "lat": 35.313056,
      "lng": 139.534167,
      "original_lat": 35.308056,
      "original_lng": 139.550278,
      "移動時間": "徒歩3分",
      "滞在時間": "1時間",
      "opening_hours": [
        "月曜日: 9:00 - 17:00",
        "火曜日: 9:00 - 17:00",
        "水曜日: 定休日",
        "木曜日: 9:00 - 17:00",
        "金曜日: 9:00 - 17:00",
        "土曜日: 9:00 - 17:00",
        "日曜日: 9:00 - 17:00"
      ],
      "meal": "カフェ",
      "URL": "https://example-cafe.com/"
    }
  ],
  "travel_steps": [
    {
      "from_index": 0,
      "to_index": 1,
      "steps": [
        {
          "mode": "徒歩",
          "duration": "8分",
          "duration_str": "8分",
          "duration_minutes": 8,
          "instructions": "鎌倉大仏殿から長谷寺方面へ向かい、長谷観音前交差点を直進"
        }
      ]
    },
    {
      "from_index": 1,
      "to_index": 2, 
      "steps": [
        {
          "mode": "徒歩",
          "duration": "3分",
          "duration_str": "3分", 
          "duration_minutes": 3,
          "instructions": "長谷寺の参道を下り、長谷観音前の商店街エリア"
        }
      ]
    }
  ],
  "travels": [
    {
      "from_index": 0,
      "to_index": 1,
      "steps": [
        {
          "mode": "徒歩",
          "duration": "8分",
          "duration_str": "8分",
          "duration_minutes": 8,
          "instructions": "鎌倉大仏殿から長谷寺方面へ向かい、長谷観音前交差点を直進"
        }
      ]
    }
  ]
}

まとめ

旅行計画の生成のアルゴリズムというか仕組みの概要を書きました。正直Google Maps APIを多量に使いすぎているので、旅行計画のような気軽にto C向けのサービスで使うのは不向きで、to B向けなら何とか、な気がしています。

Discussion