今天,我们将深入探索Neo4j GraphRAG从零开始系列的另一个激动人心的篇章。在这本文中,我们将探讨如何使用Streamlit构建一个交互式前端。将引导你创建一个用户友好的界面,充分利用我们后端系统的强大功能。
目录设置
在我们开始编码之前,请确保你的项目结构组织得当。以下是你为Streamlit应用程序所需的目录结构。
Streamlit应用程序将放置在你的chatbot_backend/services/v1文件夹内。请导航到该目录并执行以下命令:
$ mkdir streamlit_app
$ cd steamlit_app
$ touch __init__.py requirements.txt config.py utils.py app.py
├── chatbot_backend
│ ├── ci_cd
│ │ └── docker
│ │ ├── fastapi.dockerfile
│ │ └── streamlit.dockerfile
│ ├── docker-compose.yaml
│ ├── infrastructure
│ ├── __pycache__
│ │ └── main.cpython-310.pyc
│ ├── services
│ │ └── v1
│ │ ├── agents
│ │ │ ├── __init__.py
│ │ │ └── main_agent.py
│ │ ├── chains
│ │ │ ├── cypher_query_chain.py
│ │ │ ├── employee_query_chain.py
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ ├── main.py
│ │ ├── requirements.txt
│ │ ├── schemas
│ │ │ └── __init__.py
│ │ ├── streamlit_app
│ │ │ ├── app.py
│ │ │ ├── config.py
│ │ │ ├── __init__.py
│ │ │ ├── requirements.txt
│ │ │ └── utils.py
│ │ └── utils
│ │ └── __init__.py
│ └── tools
│ ├── employee_query_tool.py
│ ├── general_query_tool.py
│ └── __init__.py
├── codes
│ ├── chatbot.ipynb
│ └── ingest.ipynb
├── data
│ ├── categories.csv
│ ├── customers.csv
│ ├── employees.csv
│ ├── employee_territories.csv
│ ├── order_details.csv
│ ├── orders.csv
│ ├── products.csv
│ ├── regions.csv
│ ├── shippers.csv
│ ├── suppliers.csv
│ └── territories.csv
├── docker-compose.yml
├── ETL_pipelines
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── main_etl.py
└── requirements.txt
16 directories, 40 files
库和包的安装
首先,我们来为我们的前端设置Streamlit。由于我们将使用Docker将应用程序容器化,而不是在主机上运行它,因此我们只需要在chatbot_backend/services/v1/streamlit_app/requirements.txt文件中更新我们的依赖项。
streamlit>=1.31.0
requests>=2.31.0
python-dotenv>=1.0.0
更新文件内容
我们开始配置Streamlit应用程序。首先,我们将设置chatbot_backend/services/v1/streamlit_app/config.py文件:
import os
class Config:
# Use container name when running in Docker, fallback to localhost for local development
BACKEND_URL = os.getenv("BACKEND_URL", "http://fastapi_app:8000")
APP_TITLE = "Chatbot Interface"
APP_DESCRIPTION = "This chatbot helps you query information about employees and other business data."
现在,让我们在chatbot_backend/services/v1/streamlit_app/utils.py文件中创建实用函数。这些函数将处理与后端应用程序通信等重要任务:
import requests
import streamlit as st
from config import Config
def send_message(message: str) -> str:
"""
Send message to the FastAPI backend and handle response
"""
try:
response = requests.post(
f"{Config.BACKEND_URL}/chat",
params={"query": message},
timeout=120
)
response.raise_for_status()
data = response.json()
# Simply return the response dict
return data
except requests.exceptions.ConnectionError:
error_msg = f"Unable to connect to backend at {Config.BACKEND_URL}"
st.error(error_msg)
return {"error": error_msg}
except requests.exceptions.RequestException as e:
error_msg = f"Error: {str(e)}"
st.error(error_msg)
return {"error": error_msg}
让我们在app.py文件中构建主要的Streamlit应用程序。这将作为我们前端的核心,把我们创建的所有组件整合在一起:
import streamlit as st
from config import Config
from utils import send_message
import json
# Custom CSS to reduce sidebar width and adjust padding
st.markdown("""
<style>
[data-testid="stSidebar"][aria-expanded="true"]{
min-width: 250px;
max-width: 250px;
}
[data-testid="stSidebar"][aria-expanded="false"]{
margin-left: -250px;
}
section[data-testid="stSidebarContent"] {
padding-top: 1rem;
padding-right: 1rem;
}
.stButton button {
width: 100%;
}
div[data-testid="stExpander"] {
background-color: #262730;
}
</style>
""", unsafe_allow_html=True)
# Initialize session state
if "messages" not in st.session_state:
st.session_state.messages = []
if "show_steps" not in st.session_state:
st.session_state.show_steps = False
def main():
# Minimal sidebar
with st.sidebar:
st.write("### Settings")
# Compact URL input
backend_url = st.text_input(
"Backend URL",
value=Config.BACKEND_URL,
key="backend_url",
label_visibility="collapsed"
)
if backend_url:
Config.BACKEND_URL = backend_url
# Checkbox in a more compact form
st.session_state.show_steps = st.checkbox(
"Show context",
value=False,
help="Display supporting information"
)
# Add a small divider
st.divider()
# Minimal about section
st.write("##### About")
st.write("Query employee & business data")
# Rest of your app code remains the same...
st.title("Chatbot Interface")
# Display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
if message["role"] == "user":
st.markdown(message["content"])
else:
try:
output_dict = message["content"]
st.markdown(output_dict.get(
"Answer", "No answer available"))
with st.expander("Context Used To Provide Answer", expanded=st.session_state.show_steps):
st.json(output_dict.get("Context", []))
except: # noqa: E722
st.markdown(message["content"])
# Chat input
if prompt := st.chat_input("What would you like to know?"):
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("assistant"):
response = send_message(prompt)
if "response" in response and "output" in response["response"]:
output_str = response["response"]["output"]
st.markdown(json.loads(output_str).get(
"Answer", "No answer available"))
with st.expander("Context Used To Provide Answer", expanded=st.session_state.show_steps):
st.json(json.loads(output_str).get("Context", []))
st.session_state.messages.append({
"role": "assistant",
"content": output_str
})
else:
st.error("Unexpected response format")
if __name__ == "__main__":
main()
Streamlit应用程序的容器化
既然我们已经构建了Streamlit应用程序,接下来就让我们用Docker将其容器化。我们将重点关注两个关键步骤:
创建Dockerfile
首先,让我们在chatbot_backend/ci_cd/docker/目录下创建名为streamlit.dockerfile的Dockerfile:
FROM python:3.10-slim
WORKDIR /app
COPY services/v1/streamlit_app/requirements.txt .
RUN pip install -r requirements.txt
COPY services/v1/streamlit_app .
EXPOSE 8501
CMD ["streamlit", "run", "app.py"]
更新Docker Compose文件
让我们通过更新Docker Compose配置来将Streamlit容器集成到项目中。我们将修改chatbot_backend/docker-compose.yaml文件:
services:
fastapi:
build:
context: .
dockerfile: ./ci_cd/docker/fastapi.dockerfile
container_name: fastapi_app
ports:
- "8000:8000"
volumes:
- type: bind
source: ./services/v1
target: /src/app
read_only: true
env_file: ./.env
networks:
- app_network
streamlit:
build:
context: .
dockerfile: ./ci_cd/docker/streamlit.dockerfile
container_name: streamlit_app
ports:
- "8501:8501"
volumes:
- type: bind
source: ./services/v1/streamlit_app
target: /app
read_only: true
environment:
- BACKEND_URL=http://fastapi_app:8000 # Use container name as hostname
networks:
- app_network
depends_on:
- fastapi
networks:
app_network:
driver: bridge
一旦所有配置都完成,我们就可以使用Docker Compose同时启动我们的FastAPI后端和Streamlit前端。请导航到包含docker-compose.yaml文件的chatbot_backend目录,并运行以下命令:
docker compose up
运行命令后,你需要等待Docker安装Streamlit容器的requirements.txt文件中列出的所有依赖项。你可以在终端中监控安装进度:
一旦所有服务都运行起来,你可以访问http://localhost:8501/来进入Streamlit应用程序:
最后润色
我已经对侧边栏进行了增强,为其他开发者提供了更多关于应用程序目的和功能的信息。
结论
恭喜你完成了这次全面的GraphRAG应用程序开发之旅!你掌握了一系列令人印象深刻的技术和概念,使你站在了现代AI应用程序开发的前沿。