使用GraphRAG、Neo4j和LangChain构建后端API的Streamlit UI

2024年11月06日 由 alex 发表 147 0

今天,我们将深入探索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


2


├── 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将其容器化。我们将重点关注两个关键步骤:

  1. 创建Dockerfile
  2. 更新Docker Compose文件


创建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文件中列出的所有依赖项。你可以在终端中监控安装进度:


3


一旦所有服务都运行起来,你可以访问http://localhost:8501/来进入Streamlit应用程序:


4


5


最后润色

我已经对侧边栏进行了增强,为其他开发者提供了更多关于应用程序目的和功能的信息。


6


结论

恭喜你完成了这次全面的GraphRAG应用程序开发之旅!你掌握了一系列令人印象深刻的技术和概念,使你站在了现代AI应用程序开发的前沿。


文章来源:https://ai.gopubby.com/graphrag-with-neo4j-building-and-langchain-building-streamlit-ui-to-consume-backend-api-9e88f8370ce8
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消