「LangChain、Google Maps API、およびGradioを使用したスマートな旅行スケジュール提案システムの構築(パート3)」

「LangChain、Google Maps API、およびGradioを活用したスマートな旅行スケジュール提案システムの構築(パート3)」

次のロードトリップのインスピレーションになるアプリケーションの構築方法を学びましょう

この記事は、OpenAIとGoogle APIを使用して旅行の行程提案アプリケーションを構築し、gradioで生成されたシンプルなUIに表示する3部作の最終記事です。このパートでは、1部と2部で構築したエージェントとルート検索モジュールを組み合わせてUIを構築する方法について説明します。コードだけを見たい場合は、こちらから見つけることができます

1. 2部の要点

この3部作の2部では、LLMコールの一連のウェイポイントのパースされたリストを受け取り、Google Maps APIとFoliumを使用してそれらの間のルートを生成し、インタラクティブなマップ上に表示するシステムを構築しました。このプロジェクトの目標は、「ベルリンからチューリッヒへの4日間の旅行で、地元のビールと食べ物をたくさん試す」といった旅行リクエストを簡単に入力できるアプリケーションを構築し、詳細な行程表とマップを提供することです。1部と2部のおかげで、すべてのコンポーネントが組み立てられました。さあ、それらを使いやすいUIに組み合わせるだけです。

2. マップをgradioに接続する

gradioは、機械学習モデルをショーケースすることができるインタラクティブなアプリを迅速に構築するための優れたライブラリです。Matplotlib、Bohkeh、およびPlotlyと連携するために設計されたgradio.Plotコンポーネントがあります(詳細はこちら)。しかし、2部で生成したマップはfoliumで作成されています。これらの他のライブラリのいずれかを使用してそれらを再作成することも可能ですが、幸いなことに必要ありません。代わりに、foliumコードを再利用し、それをgradioが理解できる形式に出力するleafmapパッケージを使用できます。詳細はこちらをご覧ください。

これがどのように機能するかを示す簡単な例を見てみましょう。まず、望ましい形式のhtmlを出力する関数を作成します。

import leafmap.foliumap as leafmapimport foliumimport gradio as grdef generate_map(center_coordinates, zoom_level):    coords = center_coordinates.split(",")    lat, lon = float(coords[0]), float(coords[1])    map = leafmap.Map(location=(lat,lon), tiles="Stamen Terrain", zoom_start=zoom_level)    return map.to_gradio()

ここでは、generate_map関数はフォーマット「lat、lon」の座標の文字列とfoliumマップのズームレベルを受け取ります。マップを生成し、gradioが読み取れる形式に変換します。

次に、非常にシンプルなgradioインターフェースを構築しましょう。

demo = gr.Blocks()with demo:    gr.Markdown("## 地図を生成する")    with gr.Row():      with gr.Column():        #最初の列はボタン用        coordinates_input = gr.Textbox(value="",label="中心座標",lines=1)        zoom_level_input = gr.Dropdown(choices=[1,2,3,4,5,6,7,8,9],label="ズームレベルを選択")        map_button = gr.Button("地図を生成")      with gr.Column():        #2番目の列は地図用        map_output = gr.HTML(label="旅行地図")    map_button.click(generate_map, inputs=[coordinates_input,zoom_level_input], outputs=[map_output])# ノートブックで実行してUIを表示するには、以下を実行しますdemo.queue().launch(debug=True)

ここでは、Blocks APIを使用して、アプリのUIを柔軟に設定できるようにしています。2つの列を持つ1行のコンポーネントを作成しています。最初の列には3つの要素が含まれています。ユーザーが望む中心座標を入力するテキストボックス、ズームレベルを選択するドロップダウン、クリックする必要のある「地図を生成」という名前のボタンです。

2番目の列には、マップのhtmlを表示するgradio.HTML()コンポーネントであるmap_outputがあります。

それでは、map_buttonがクリックされたときに何が起こるかを定義する必要があります。これが起こると、coordinates_inputzoom_inputから選択された値を受け取ってgenerate_map関数を実行します。結果はmap_output変数に送信されます。

これを実行すると、以下のUIが生成されます。

Basic mapping UI generated with leafmap and gradio

これは確かに洗練されたデザインではありませんが、gradioでマッピングツールを構築するための必須要素を含んでいます。

3. 旅行代理店のためのシンプルなUI

まずはコードを調べる前に、旅行マッパーのgradioアプリのいくつかの機能を見てみましょう。ただし、gradioには多種多様なコンポーネントがあり、洗練された見た目のUIを作成するための多くのオプションが用意されています。この旅行マッパーUIはまだPOC段階にあります。

Description of all the components in the final gradio app for the travel mapper

基本的に、私たちのアプリには2つの列があります。最初の列には、ユーザがクエリを入力するためのテキストボックス、モデル間を切り替えるためのラジオボタンのセット、バリデーションチェックの出力を表示するテキストボックスがあります。

2番目の列には、leafmap.foliumを使用して生成されたマップと、LLM呼び出しの完全なテキストイティネラリ出力を表示するテキストボックスが含まれます。上のスクリーンショットでは、「マップを生成」ボタンは画面下部にあります。

gradioによってバックグラウンドで行われるすべての作業のおかげで、これらすべてのコードは非常に簡潔になっています。

import gradio as gr
from travel_mapper.TravelMapper import TravelMapperForUI, load_secrets, assert_secrets
from travel_mapper.user_interface.utils import generate_generic_leafmap
from travel_mapper.user_interface.constants import EXAMPLE_QUERY

def main():
    # APキーをロードする
    secrets = load_secrets()
    assert_secrets(secrets)
    
    # 旅行マッパーをセットアップする(part 2を参照)
    travel_mapper = TravelMapperForUI(
        openai_api_key=secrets["OPENAI_API_KEY"],
        google_maps_key=secrets["GOOGLE_MAPS_API_KEY"],
        google_palm_api_key=secrets["GOOGLE_PALM_API_KEY"],
    )
    
    # gradioでUIを構築する
    app = gr.Blocks()
    
    # アプリが最初にロードされたときに表示する汎用のマップを作成する
    generic_map = generate_generic_leafmap()
    
    with app:
        gr.Markdown("## 旅行の提案を生成")
        
        # 複数のタブを作成する
        with gr.Tabs():
            # 最初のタブを作成する
            with gr.TabItem("マップを使用して生成"):
                # タブ1内の行1を作成する
                with gr.Row():
                    # 行1内の列1を作成する
                    with gr.Column():
                        text_input_map = gr.Textbox(
                            EXAMPLE_QUERY, label="旅行クエリ", lines=4
                        )
                        radio_map = gr.Radio(
                            value="gpt-3.5-turbo",
                            choices=["gpt-3.5-turbo", "gpt-4", "models/text-bison-001"],
                            label="モデル",
                        )
                        query_validation_text = gr.Textbox(
                            label="クエリのバリデーション情報", lines=2
                        )
                    
                    # 行1内の列2を作成する
                    with gr.Column():
                        # マップが表示される場所
                        map_output = gr.HTML(generic_map, label="旅行マップ")
                        # 提案された旅行が表示される場所
                        itinerary_output = gr.Textbox(
                            value="ここにイティネラリが表示されます",
                            label="旅程の提案",
                            lines=3,
                        )
                
                # 生成ボタン
                map_button = gr.Button("生成")
            
            # 2番目のタブを作成する
            with gr.TabItem("マップなしで生成"):
                # 2番目のタブ内の最初の行を作成する
                with gr.Row():
                    # 最初の行内の最初の列を作成する
                    with gr.Column():
                        text_input_no_map = gr.Textbox(
                            value=EXAMPLE_QUERY, label="旅行クエリ", lines=3
                        )
                        radio_no_map = gr.Radio(
                            value="gpt-3.5-turbo",
                            choices=["gpt-3.5-turbo", "gpt-4", "models/text-bison-001"],
                            label="モデルの選択肢",
                        )
                        query_validation_no_map = gr.Textbox(
                            label="クエリのバリデーション情報", lines=2
                        )
                    
                    # 最初の行内の2番目の列を作成する
                    with gr.Column():
                        text_output_no_map = gr.Textbox(
                            value="ここにイティネラリが表示されます",
                            label="旅程の提案",
                            lines=3,
                        )
                
                # 生成ボタン
                text_button = gr.Button("生成")
        
        # ボタンがクリックされたときの処理の指示
        # ここでは"generate_with_leafmap"メソッドの使用に注目してください
        map_button.click(
            travel_mapper.generate_with_leafmap,
            inputs=[text_input_map, radio_map],
            outputs=[map_output, itinerary_output, query_validation_text],
        )
        text_button.click(
            travel_mapper.generate_without_leafmap,
            inputs=[text_input_no_map, radio_no_map],
            outputs=[text_output_no_map, query_validation_no_map],
        )
        
        # アプリを実行する
        app.launch()

4. パッケージの作成

GitHubのリポジトリを見るとわかるように、旅行マッパーのコードはcookiecutterの標準テンプレートを使用して構造化されていますが、テンプレートのいくつかの重要な部分がまだ埋まっていません。理想的には、ユニットテストと統合テストを含め、リポジトリのセットアップを完了し、継続的インテグレーション/継続的デリバリー(CI/CD)のコンセプトを使用します。このPOCステージを超えてプロジェクトがさらに発展する場合、これらの側面は将来的に追加されます。

コードをローカルで実行するためのいくつかの方法があります。上記のmain関数をdriver.pyというスクリプトに配置すれば、travel_mapperプロジェクトのトップレベルからターミナルで実行できるはずです。パッケージが正常に実行された場合、ターミナルには次のようなメッセージが表示されます。

ローカルURLで実行中:  http://127.0.0.1:7860

このURLをWebブラウザにコピーして貼り付けると、マシン上でローカルに実行されているGradioアプリが表示されます。もちろん、実際にウェブ上に展開する場合には(API呼び出しに関連する費用が発生するためお勧めしませんが)、さらに手順が必要ですが、それはこの記事の範囲を超えています。

ドライバは、run.shというBashスクリプトからも実行できます。このスクリプトは、コードベースのuser_interfaceモジュールにあります。

# UIを実行# これはトラベルマッパーのプロジェクトのトップレベルディレクトリから実行しますexport PYTHONPATH=$PYTHONPATH:$(pwd)echo "トラベルマッパーUIを起動中"$(pwd)/travel_mapper/user_interface/driver.py

プロジェクトのトップレベルから実行すると、PYTHONPATHが正しく設定されるため、プロジェクト固有のインポート文が常に認識されます。

以上がこのシリーズの内容であり、お読みいただきありがとうございます!フルコードベースはこちらで公開されています:https://github.com/rmartinshort/travel_mapper。改善の提案や機能の拡張に関するご意見は大歓迎です!

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more