使用LangChain、Google Maps API和Gradio构建智能旅行行程建议工具(第3部分)
“打造智能旅行行程建议工具:LangChain、Google Maps API和Gradio的结合(第3部分)”
学习如何构建一个可能激发您下一次公路旅行灵感的应用程序
This article is the final one in a three part series where we build a travel itinerary suggester application using OpenAI and Google APIs and display it in a simple UI generated with gradio. In this part, we discuss how to build that UI, putting together the Agent and RouteFinder modules that we built in parts 1 and 2. Just want see the code? Find it here.
1. 第2部分回顾
在这个三部分系列的第二部分中,我们构建了一个使用OpenAI和Google APIs构建旅行行程建议应用程序,并在使用gradio生成的简单UI中展示它们。在本part中,我们讨论如何构建该UI,将我们在第1部分和第2部分中构建的Agent和RouteFinder模块组合在一起。只想看代码?在这里找到它
2. 将地图连接到gradio
gradio是一个出色的库,可以快速构建展示机器学习模型的交互式应用程序。它具有与Matplotlib、Bohkeh和Plotly兼容的gradio.Plot组件(详细信息在这里)。然而,我们在第二部分中生成的地图是使用folium制作的。我们可以用这些其他库之一重新制作它们,但我们不需要这样做。相反,我们可以使用leafmap软件包,它允许我们重用已经有的folium代码,并将其强制转换为gradio可以理解的html格式。详情可以在这里找到。
让我们看一个简单的示例,看看它是如何工作的。首先,我们将创建一个以所需格式输出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("## Generate a map") with gr.Row(): with gr.Column(): # 第一列是按钮 coordinates_input = gr.Textbox(value="",label="Your center coordines",lines=1) zoom_level_input = gr.Dropdown(choices=[1,2,3,4,5,6,7,8,9],label="choose zoom level") map_button = gr.Button("Generate map") with gr.Column(): # 第二列是地图 map_output = gr.HTML(label="Travel map") map_button.click(generate_map, inputs=[coordinates_input,zoom_level_input], outputs=[map_output])# 在笔记本中运行以显示界面demo.queue().launch(debug=True)
在这里,我们使用了Blocks API,它使我们能够灵活地设置应用程序的UI。我们创建了一行组件,有两列。第一列包含三个元素:一个文本框,用户可以输入所需的中心坐标,一个下拉列表框,用于选择缩放级别,并一个名为“生成地图”的按钮,用户需要点击它。
在第二列中,我们有一个map_output,这是一个gradio.HTML()组件,将显示地图html。
然后,我们所需要做的就是定义当map_button
被点击时发生的事情。在这种情况下,我们将运行generate_map
函数,将从coordinates_input
和zoom_input
中选择的值传递进去。结果将发送到map_output
变量。
运行后,会生成以下用户界面:
这个界面虽然没有太多精细或合理布局的地方,但它包含了使用gradio构建地图工具所需的基本元素。
3. 一个简单的旅行顾问用户界面
在我们检查代码之前,让我们先看看旅行顾问gradio应用程序的一些特点。请牢记,gradio提供了大量可用于创建复杂和美观用户界面的组件,而这个旅行顾问界面仍然处于原型阶段。
我们的应用程序基本上有两列。第一列包含一个文本框,供用户输入查询内容,一组单选按钮,允许我们在模型之间切换,以及一个文本框,显示验证检查的输出。
第二列包含地图(使用leafmap.folium
生成)和一个文本框,显示LLM调用的完整短行程输出。上面的屏幕截图中,“生成地图”按钮在屏幕底部。
由于gradio在后台执行了大量工作,所以整个代码显得非常简洁。
import gradio as grfrom travel_mapper.TravelMapper import TravelMapperForUI, load_secrets, assert_secretsfrom travel_mapper.user_interface.utils import generate_generic_leafmapfrom travel_mapper.user_interface.constants import EXAMPLE_QUERYdef main(): # 加载API密钥 secrets = load_secrets() assert_secrets(secrets) # 设置旅行顾问(见第二部分) 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中构建用户界面 app = gr.Blocks() # 当应用程序第一次加载时生成一个通用地图 generic_map = generate_generic_leafmap() with app: gr.Markdown("## 生成旅行建议") # 创建多个选项卡 with gr.Tabs(): # 创建第一个选项卡 with gr.TabItem("使用地图生成"): # 创建在第一个选项卡中的第一行 with gr.Row(): # 创建在第一行中的第一列 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 ) # 创建在第一行中的第二列 with gr.Column(): # 显示地图的位置 map_output = gr.HTML(generic_map, label="旅行地图") # 显示建议行程的位置 itinerary_output = gr.Textbox( value="此处将显示您的行程", label="行程建议", lines=3, ) # 生成按钮 map_button = gr.Button("生成") # 创建第二个选项卡 with gr.TabItem("不使用地图生成"): # 在第二个选项卡中创建第一行 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 ) # 在第一行中创建第二列 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
项目的顶级目录中运行它。如果软件包成功运行,则终端会显示以下消息:
Running on local URL: http://127.0.0.1:7860
将此网址复制粘贴到Web浏览器中,应在本机上显示出gradio应用程序运行。当然,如果我们真的想要将其部署到Web上(由于API调用所产生的成本,我不建议这样做),还需要更多的步骤,但这超出了这些文章的范围。
驱动程序还可以从名为run.sh
的bash脚本中运行,该脚本可以在代码库的user_interface
模块中找到。
# Run the UI# run this from the top level directory of the travel mapper projectexport PYTHONPATH=$PYTHONPATH:$(pwd)echo "Starting travel mapper UI"$(pwd)/travel_mapper/user_interface/driver.py
从项目的顶级目录运行时,这也会正确设置PYTHONPATH
,以便始终识别项目特定的导入语句。
系列文章到此结束,感谢您一直阅读到最后!请随时在此处https://github.com/rmartinshort/travel_mapper探索完整的代码库。如有任何改进或功能扩展的建议,将不胜感激!