Skip to content

用 Delphic 构建全栈 LlamaIndex Web 应用指南#

本指南旨在带领您使用 LlamaIndex 与一个名为 Delphic 的生产就绪 Web 应用起始模板。这里的所有代码示例都可以从 Delphic 仓库获取。

我们要构建什么#

以下是 Delphic 的开箱即用功能的快速演示:

Delphic Demo

架构概述#

Delphic 利用 LlamaIndex Python 库,让用户创建自己的文档集合,然后可以在响应式前端进行查询。

我们选择了一组技术,提供了响应式、强大的技术组合,可以 (1) 编排复杂的 Python 处理任务,同时提供 (2) 现代、响应式的前端和 (3) 安全的后端,以构建额外的功能。

核心库包括:

  1. Django
  2. Django Channels
  3. Django Ninja
  4. Redis
  5. Celery
  6. LlamaIndex
  7. Langchain
  8. React
  9. Docker & Docker Compose

由于这个现代化的技术栈建立在非常稳定的 Django Web 框架上,起始的 Delphic 应用具有简化的开发者体验、内置的身份验证和用户管理、异步向量存储处理以及基于 Web Socket 的查询连接,以实现响应式用户界面。此外,我们的前端是使用 TypeScript 构建的,基于 MUI React,实现了响应式和现代化的用户界面。

系统要求#

Celery 不支持 Windows。它可能可以在 Windows Subsystem for Linux 上部署,但配置这一点超出了本教程的范围。因此,我们建议您只在运行 Linux 或 OSX 的情况下遵循本教程。您需要安装 Docker 和 Docker Compose 来部署应用程序。本地开发将需要使用 node 版本管理器 (nvm)。

Django 后端#

项目目录概述#

Delphic 应用有一个结构化的后端目录组织,遵循常见的 Django 项目约定。从仓库根目录,在 ./delphic 子文件夹中,主要的文件夹有:

  1. contrib: 此目录包含对 Django 内置的 contrib 应用的自定义修改或添加。
  2. indexes: 此目录包含与文档索引和 LLM 集成相关的核心功能。它包括:

  3. admin.py: 应用的 Django 管理配置

  4. apps.py: 应用配置
  5. models.py: 包含应用的数据库模型
  6. migrations: 包含应用的数据库模式迁移
  7. signals.py: 为应用定义任何信号
  8. tests.py: 应用的单元测试

  9. tasks: 此目录包含使用 Celery 进行异步处理的任务。index_tasks.py 文件包括用于创建向量索引的任务。

  10. users: 此目录专门用于用户管理,包括:
  11. utils: 此目录包含在整个应用程序中使用的实用模块和函数,例如自定义存储后端、路径助手和与集合相关的实用程序。

数据库模型#

Delphic 应用有两个核心模型:DocumentCollection。这些模型代表应用在使用 LLM 进行文档索引和查询时所处理的中心实体。它们在 ./delphic/indexes/models.py 中定义。

  1. Collection:

  2. api_key: 将集合与 API 密钥关联起来的外键。这有助于将作业与源 API 密钥关联起来。

  3. title: 为集合提供标题的字符字段。
  4. description: 提供集合描述的文本字段。
  5. status: 存储集合处理状态的字符字段,利用 CollectionStatus 枚举。
  6. created: 记录集合创建时间的日期时间字段。
  7. modified: 记录集合最后修改时间的日期时间字段。
  8. model: 存储与集合关联的模型的文件字段。
  9. processing: 布尔字段,指示集合当前是否正在处理。

  10. Document:

  11. collection: 将文档与集合关联起来的外键。这代表文档和集合之间的关系。

  12. file: 存储上传的文档文件的文件字段。
  13. description: 提供文档描述的文本字段。
  14. created: 记录文档创建时间的日期时间字段。
  15. modified: 记录文档最后修改时间的日期时间字段。 这些模型为使用 LlamaIndex 创建的文档集合和索引提供了坚实的基础。

Django Ninja API#

Django Ninja 是一个用于使用 Django 和 Python 3.7+ 类型提示构建 API 的 Web 框架。它提供了一种简单、直观和富有表现力的方式来定义 API 端点,利用 Python 的类型提示自动生成输入验证、序列化和文档。

在 Delphic 存储库中,./config/api/endpoints.py 文件包含了 API 端点的路由和逻辑。现在,让我们简要介绍一下 endpoints.py 文件中每个端点的目的:

  1. /heartbeat:一个简单的 GET 端点,用于检查 API 是否正常运行。如果 API 可访问,则返回 True。这对于期望能够查询容器以确保其正常运行的 Kubernetes 设置非常有帮助。

  2. /collections/create:一个用于创建新的 Collection 的 POST 端点。接受表单参数,如 titledescriptionfiles 列表。为每个文件创建一个新的 CollectionDocument 实例,并安排一个 Celery 任务来创建索引。

@collections_router.post("/create")
async def create_collection(
    request,
    title: str = Form(...),
    description: str = Form(...),
    files: list[UploadedFile] = File(...),
):
    key = None if getattr(request, "auth", None) is None else request.auth
    if key is not None:
        key = await key

    collection_instance = Collection(
        api_key=key,
        title=title,
        description=description,
        status=CollectionStatusEnum.QUEUED,
    )

    await sync_to_async(collection_instance.save)()

    for uploaded_file in files:
        doc_data = uploaded_file.file.read()
        doc_file = ContentFile(doc_data, uploaded_file.name)
        document = Document(collection=collection_instance, file=doc_file)
        await sync_to_async(document.save)()

    create_index.si(collection_instance.id).apply_async()

    return await sync_to_async(CollectionModelSchema)(...)
  1. /collections/query:一个用于使用 LLM 查询文档集合的 POST 端点。接受一个包含 collection_idquery_str 的 JSON 负载,并返回通过查询集合生成的响应。我们实际上并不在我们的聊天 GUI 中使用这个端点(我们使用了一个 websocket - 请参见下文),但您可以构建一个应用程序来集成到这个 REST 端点,以查询特定的集合。
@collections_router.post(
    "/query",
    response=CollectionQueryOutput,
    summary="Ask a question of a document collection",
)
def query_collection_view(
    request: HttpRequest, query_input: CollectionQueryInput
):
    collection_id = query_input.collection_id
    query_str = query_input.query_str
    response = query_collection(collection_id, query_str)
    return {"response": response}
  1. /collections/available:一个 GET 端点,返回使用用户的 API 密钥创建的所有集合的列表。输出使用 CollectionModelSchema 进行序列化。
@collections_router.get(
    "/available",
    response=list[CollectionModelSchema],
    summary="Get a list of all of the collections created with my api_key",
)
async def get_my_collections_view(request: HttpRequest):
    key = None if getattr(request, "auth", None) is None else request.auth
    if key is not None:
        key = await key

    collections = Collection.objects.filter(api_key=key)

    return [{...} async for collection in collections]
  1. /collections/{collection_id}/add_file:一个用于向现有集合添加文件的 POST 端点。接受 collection_id 路径参数,以及诸如 filedescription 的表单参数。将文件作为与指定集合关联的 Document 实例添加。
@collections_router.post(
    "/{collection_id}/add_file", summary="Add a file to a collection"
)
async def add_file_to_collection(
    request,
    collection_id: int,
    file: UploadedFile = File(...),
    description: str = Form(...),
):
    collection = await sync_to_async(Collection.objects.get)(id=collection_id)

WebSocket 简介#

WebSockets 是一种通信协议,它能够在单个、长期存在的连接上实现客户端和服务器之间的双向全双工通信。WebSocket 协议设计用于在与 HTTP 和 HTTPS 相同的端口上工作(分别为端口 80 和 443),并使用类似的握手过程来建立连接。一旦建立了连接,数据可以作为“帧”在两个方向上发送,而无需每次重新建立连接,这与传统的 HTTP 请求不同。

使用 WebSocket 有几个原因,特别是在处理需要长时间加载到内存中但一旦加载就能快速运行的代码时: 1. 性能: WebSockets 消除了为每个请求打开和关闭多个连接所带来的开销,降低了延迟。 2. 效率: WebSockets 允许实时通信,无需轮询,从而更有效地利用资源并提高响应速度。 3. 可扩展性: WebSockets 能够处理大量同时连接,非常适合需要高并发的应用程序。

对于 Delphic 应用程序来说,使用 WebSockets 是有道理的,因为将 LLMs 加载到内存中可能会很昂贵。通过建立 WebSocket 连接,LLM 可以保持在内存中,从而使后续请求能够快速处理,而无需每次重新加载模型。

ASGI 配置文件 ./config/asgi.py 定义了应用程序如何处理传入的连接,使用 Django Channels 的 ProtocolTypeRouter 根据其协议类型路由连接。在这种情况下,有两种协议类型:"http" 和 "websocket"。

“http” 协议类型使用标准的 Django ASGI 应用程序来处理 HTTP 请求,而 “websocket” 协议类型使用自定义的 TokenAuthMiddleware 来验证 WebSocket 连接。TokenAuthMiddleware 中的 URLRouter 定义了 CollectionQueryConsumer 的 URL 模式,负责处理与查询文档集相关的 WebSocket 连接。

application = ProtocolTypeRouter(
    {
        "http": get_asgi_application(),
        "websocket": TokenAuthMiddleware(
            URLRouter(
                [
                    re_path(
                        r"ws/collections/(?P<collection_id>\w+)/query/$",
                        CollectionQueryConsumer.as_asgi(),
                    ),
                ]
            )
        ),
    }
)

这个配置允许客户端与 Delphic 应用程序建立 WebSocket 连接,以高效地使用 LLMs 查询文档集,而无需为每个请求重新加载模型。

WebSocket 处理程序#

config/api/websockets/queries.py 中的 CollectionQueryConsumer 类负责处理与查询文档集相关的 WebSocket 连接。它继承自 Django Channels 提供的 AsyncWebsocketConsumer 类。

CollectionQueryConsumer 类有三个主要方法:

  1. connect: 在 WebSocket 作为连接过程的一部分进行握手时调用。
  2. disconnect: 当 WebSocket 因任何原因关闭时调用。
  3. receive: 当服务器从 WebSocket 接收消息时调用。

WebSocket 连接监听器#

connect 方法负责建立连接,从连接路径中提取集合 ID,加载集合模型,并接受连接。

async def connect(self):
    try:
        self.collection_id = extract_connection_id(self.scope["path"])
        self.index = await load_collection_model(self.collection_id)
        await self.accept()

    except ValueError as e:
        await self.accept()
        await self.close(code=4000)
    except Exception as e:
        pass

WebSocket 断开连接监听器#

在这种情况下,disconnect 方法为空,因为当 WebSocket 关闭时没有其他操作需要执行。

WebSocket 接收监听器#

receive 方法负责处理来自 WebSocket 的传入消息。它接收传入消息,对其进行解码,然后使用提供的查询查询加载的集合模型。然后将响应格式化为 markdown 字符串,并通过 WebSocket 连接发送回客户端。

async def receive(self, text_data):
    text_data_json = json.loads(text_data)

    if self.index is not None:
        query_str = text_data_json["query"]
        modified_query_str = f"请返回一个格式良好的 markdown 字符串以响应此请求:\n\n{query_str}"
        query_engine = self.index.as_query_engine()
        response = query_engine.query(modified_query_str)

        markdown_response = f"## 响应\n\n{response}\n\n"
        if response.source_nodes:
            markdown_sources = (
                f"## 源\n\n{response.get_formatted_sources()}"
            )
        else:
            markdown_sources = ""

        formatted_response = f"{markdown_response}{markdown_sources}"

        await self.send(json.dumps({"response": formatted_response}, indent=4))
    else:
        await self.send(
            json.dumps(
                {"error": "此连接未加载索引。"}, indent=4
            )
        )

要加载集合模型,使用 load_collection_model 函数,该函数可以在 [20] 中找到。 在 delphic/utils/collections.py 中。这个函数会检索具有给定集合 ID 的集合对象,检查集合模型的 JSON 文件是否存在,如果不存在,则创建一个。然后,在加载 VectorStoreIndex 之前,它会设置 LLMSettings

from llama_index.core import Settings


async def load_collection_model(collection_id: str | int) -> VectorStoreIndex:
    """
    从缓存或数据库加载 Collection 模型,并返回索引。

    Args:
        collection_id (Union[str, int]): Collection 模型实例的 ID。

    Returns:
        VectorStoreIndex: 加载的索引。

    此函数执行以下步骤:
    1. 检索具有给定 collection_id 的 Collection 对象。
    2. 检查名为 '/cache/model_{collection_id}.json' 的 JSON 文件是否存在。
    3. 如果 JSON 文件不存在,则从 Collection.model FileField 加载 JSON 并保存到 '/cache/model_{collection_id}.json'。
    4. 使用缓存文件路径调用 VectorStoreIndex.load_from_disk。
    """
    # 检索 Collection 对象
    collection = await Collection.objects.aget(id=collection_id)
    logger.info(f"load_collection_model() - loaded collection {collection_id}")

    # 确保有模型
    if collection.model.name:
        logger.info("load_collection_model() - Setup local json index file")

        # 检查 JSON 文件是否存在
        cache_dir = Path(settings.BASE_DIR) / "cache"
        cache_file_path = cache_dir / f"model_{collection_id}.json"
        if not cache_file_path.exists():
            cache_dir.mkdir(parents=True, exist_ok=True)
            with collection.model.open("rb") as model_file:
                with cache_file_path.open(
                    "w+", encoding="utf-8"
                ) as cache_file:
                    cache_file.write(model_file.read().decode("utf-8"))

        # 定义 LLM
        logger.info(
            f"load_collection_model() - Setup Settings with tokens {settings.MAX_TOKENS} and "
            f"model {settings.MODEL_NAME}"
        )
        Settings.llm = OpenAI(
            temperature=0, model="gpt-3.5-turbo", max_tokens=512
        )

        # 调用 VectorStoreIndex.load_from_disk
        logger.info("load_collection_model() - Load llama index")
        index = VectorStoreIndex.load_from_disk(
            cache_file_path,
        )
        logger.info(
            "load_collection_model() - Llamaindex loaded and ready for query..."
        )

    else:
        logger.error(
            f"load_collection_model() - collection {collection_id} has no model!"
        )
        raise ValueError("No model exists for this collection!")

    return index

React 前端#

概述#

我们选择在 Delphic 项目的前端使用 TypeScript、React 和 Material-UI(MUI)有几个原因。首先,作为最流行的前端框架(React)的最受欢迎的组件库(MUI),这个选择使得这个项目能够吸引到一个庞大的开发者社区。其次,React 目前是一个稳定且广受好评的框架,它通过虚拟 DOM 提供了有价值的抽象,同时相对稳定,并且在我们看来,相当容易学习,这也使得它更具吸引力。

前端项目结构#

前端代码可以在仓库的 /frontend 目录中找到,与 React 相关的组件位于 /frontend/src 中。您会注意到在 frontend 目录中有一个 DockerFile,以及几个与配置前端 Web 服务器(nginx)相关的文件和文件夹。

/frontend/src/App.tsx 文件作为应用程序的入口点。它定义了主要组件,如登录表单、抽屉布局和集合创建模态框。这些主要组件是根据用户是否已登录并具有身份验证令牌进行有条件地渲染的。

DrawerLayout2 组件定义在 DrawerLayour2.tsx 文件中。该组件管理应用程序的布局,并提供导航和主要内容区域。

由于应用程序相对简单,我们可以不使用像 Redux 这样复杂的状态管理解决方案,而只使用 React 的 useState 钩子。

从后端获取集合#

已登录用户可用的集合是在 DrawerLayout2 组件中检索并显示的。该过程可以分解为以下步骤:

  1. 初始化状态变量:
const [collections, setCollections] = useState<CollectionModelSchema[]>([]);
const [loading, setLoading] = useState(true);

在这里,我们初始化了两个状态变量:collections 用于存储集合列表,loading 用于跟踪集合是否正在被获取。

  1. 使用 fetchCollections() 函数获取已登录用户的收藏集合:
const fetchCollections = async () => {
  try {
    const accessToken = localStorage.getItem("accessToken");
    if (accessToken) {
      const response = await getMyCollections(accessToken);
      setCollections(response.data);
    }
  } catch (error) {
    console.error(error);
  } finally {
    setLoading(false);
  }
};

fetchCollections 函数通过调用 getMyCollections API 函数并传入用户的访问令牌来检索已登录用户的收藏集合。然后使用检索到的数据更新 collections 状态,并将 loading 状态设置为 false,表示获取完成。

显示收藏集合#

最新的收藏集合在抽屉中显示如下:

<List>
  {collections.map((collection) => (
    <div key={collection.id}>
      <ListItem disablePadding>
        <ListItemButton
          disabled={
            collection.status !== CollectionStatus.COMPLETE ||
            !collection.has_model
          }
          onClick={() => handleCollectionClick(collection)}
          selected={
            selectedCollection &&
            selectedCollection.id === collection.id
          }
        >
          <ListItemText
            primary={collection.title}
          />
          {collection.status === CollectionStatus.RUNNING ? (
            <CircularProgress
              size={24}
              style={{ position: "absolute", right: 16 }}
            />
          ) : null}
        </ListItemButton>
      </ListItem>
    </div>
  ))}
</List>

你会注意到,收藏集合的 ListItemButtondisabled 属性基于收藏集合的状态是否不是 CollectionStatus.COMPLETE 或者收藏集合没有模型 (!collection.has_model) 而设置。如果这两个条件中的任何一个为真,则按钮将被禁用,防止用户选择未完成或没有模型的收藏集合。当 CollectionStatus 为 RUNNING 时,我们还会在按钮上显示一个加载轮。

在单独的 useEffect 钩子中,我们检查 collections 状态中是否有任何收藏集合的状态为 CollectionStatus.RUNNINGCollectionStatus.QUEUED。如果有,我们会建立一个间隔,每 15 秒(15,000 毫秒)重复调用 fetchCollections 函数以更新收藏集合的状态。这样,应用程序会定期检查已完成的收藏集合,并在处理完成时相应地更新用户界面。

useEffect(() => {
  let interval: NodeJS.Timeout;
  if (
    collections.some(
      (collection) =>
        collection.status === CollectionStatus.RUNNING ||
        collection.status === CollectionStatus.QUEUED
    )
  ) {
    interval = setInterval(() => {
      fetchCollections();
    }, 15000);
  }
  return () => clearInterval(interval);
}, [collections]);

聊天视图组件#

frontend/src/chat/ChatView.tsx 中的 ChatView 组件负责处理和显示用户与收藏集合交互的聊天界面。该组件建立了一个 WebSocket 连接,实时与服务器通信,发送和接收消息。

ChatView 组件的关键特点包括:

  1. 建立和管理与服务器的 WebSocket 连接。
  2. 以聊天样式显示用户和服务器的消息。
  3. 处理用户输入以向服务器发送消息。
  4. 根据从服务器接收的消息更新消息状态和用户界面。
  5. 显示连接状态和错误,例如加载消息、连接到服务器或在加载收藏集合时遇到错误。

所有这些使用户能够以非常流畅、低延迟的体验与所选收藏集合进行交互。

聊天 WebSocket 客户端#

ChatView 组件中的 WebSocket 连接用于建立客户端和服务器之间的实时通信。WebSocket 连接在 ChatView 组件中设置和管理如下:

首先,我们要初始化 WebSocket 引用:

const websocket = useRef<WebSocket | null>(null);

使用 useRef 创建了一个 websocket 引用,其中保存了用于通信的 WebSocket 对象。useRef 是 React 中的一个钩子,允许你创建一个跨渲染保持不变的可变引用对象。当你需要保持对可变对象的引用,比如 WebSocket 连接,而又不想引起不必要的重新渲染时,useRef 尤为有用。

ChatView 组件中,WebSocket 连接需要在组件的整个生命周期内建立和维护,并且在连接状态发生变化时不应触发重新渲染。通过使用 useRef,你确保 WebSocket 连接被保持为引用,并且组件只在有实际状态变化时重新渲染,比如更新消息或显示错误。

setupWebsocket 函数负责建立 WebSocket 连接,并设置事件处理程序来处理不同的 WebSocket 事件。

总的来说,setupWebsocket 函数如下所示:

const setupWebsocket = () => {
  setConnecting(true);
  // 在这里,使用指定的 URL 创建了一个新的 WebSocket 对象,其中包括所选集合的 ID 和用户的身份验证令牌。

  websocket.current = new WebSocket(
    `ws://localhost:8000/ws/collections/${selectedCollection.id}/query/?token=${authToken}`,
  );

  websocket.current.onopen = (event) => {
    //...
  };

  websocket.current.onmessage = (event) => {
    //...
  };

  websocket.current.onclose = (event) => {
    //...
  };

  websocket.current.onerror = (event) => {
    //...
  };

  return () => {
    websocket.current?.close();
  };
};
在许多地方,我们根据来自网络套接字客户端的信息触发 GUI 的更新。

当组件首次打开并尝试建立连接时,将触发 onopen 监听器。在回调中,组件会更新状态以反映连接已建立,清除任何先前的错误,并且没有消息正在等待响应:

websocket.current.onopen = (event) => {
  setError(false);
  setConnecting(false);
  setAwaitingMessage(false);

  console.log("WebSocket connected:", event);
};

当通过 WebSocket 连接从服务器接收到新消息时,将触发 onmessage。在回调中,解析接收到的数据,并使用来自服务器的新消息更新 messages 状态:

websocket.current.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("WebSocket message received:", data);
  setAwaitingMessage(false);

  if (data.response) {
    // 使用来自服务器的新消息更新消息状态
    setMessages((prevMessages) => [
      ...prevMessages,
      {
        sender_id: "server",
        message: data.response,
        timestamp: new Date().toLocaleTimeString(),
      },
    ]);
  }
};

当 WebSocket 连接关闭时,将触发 onclose。在回调中,组件会检查特定的关闭代码(4000)以显示警告提示,并相应地更新组件状态。它还会记录关闭事件:

websocket.current.onclose = (event) => {
  if (event.code === 4000) {
    toast.warning(
      "Selected collection's model is unavailable. Was it created properly?",
    );
    setError(true);
    setConnecting(false);
    setAwaitingMessage(false);
  }
  console.log("WebSocket closed:", event);
};

最后,当 WebSocket 连接发生错误时,将触发 onerror。在回调中,组件会更新状态以反映错误,并记录错误事件:

websocket.current.onerror = (event) => {
  setError(true);
  setConnecting(false);
  setAwaitingMessage(false);

  console.error("WebSocket error:", event);
};

渲染我们的聊天消息#

ChatView 组件中,布局是使用 CSS 样式和 Material-UI 组件确定的。主要布局包括一个具有 flex 显示和基于列的 flexDirection 的容器。这确保容器内的内容垂直排列。

布局中有三个主要部分:

  1. 聊天消息区域:此部分占据大部分可用空间,并显示用户和服务器之间交换的消息列表。它的 overflow-y 设置为 'auto',这允许内容超出可用空间时滚动。消息使用 ChatMessage 组件呈现,每条消息都使用 ChatMessageLoading 组件显示加载状态,同时等待服务器响应。
  2. 分隔线:使用 Material-UI 的 Divider 组件将聊天消息区域与输入区域分隔开,清晰地区分了这两个部分。
  3. 输入区域:此部分位于底部,允许用户输入和发送消息。它包含来自 Material-UI 的 TextField 组件,设置为接受最多 2 行的多行输入。输入区域还包括一个 Button 组件用于发送消息。用户可以单击“发送”按钮或按键盘上的“Enter”键发送消息。

ChatView 组件接受的用户输入是用户在 TextField 中输入的文本消息。组件处理这些文本输入,并通过 WebSocket 连接将它们发送到服务器。

部署#

先决条件#

要部署该应用程序,您需要安装 Docker 和 Docker Compose。如果您使用的是 Ubuntu 或其他常见的 Linux 发行版,DigitalOcean 提供了一篇很棒的 Docker 教程,以及另一篇很棒的Docker Compose 教程供您参考。如果这些方法不适用于您,可以尝试查看官方 Docker 文档

构建和部署#

该项目基于 django-cookiecutter,很容易在虚拟机上部署并配置为为特定域提供 HTTPs 流量。然而,配置有些复杂,不是因为这个项目,而是因为配置证书、DNS 等是一个相当复杂的主题。

为了本指南的目的,让我们先在本地运行。也许我们会发布有关生产部署的指南。与此同时,可以先查看Django Cookiecutter 项目文档。 这份指南假设您的目标是让应用程序能够运行并使用。如果您想进行开发,很可能不希望使用 --profiles fullstack 标志启动组合堆栈,而是希望使用 Node 开发服务器启动 React 前端。

要部署,请首先克隆存储库:

git clone https://github.com/yourusername/delphic.git

切换到项目目录:

cd delphic

复制示例环境文件:

mkdir -p ./.envs/.local/
cp -a ./docs/sample_envs/local/.frontend ./frontend
cp -a ./docs/sample_envs/local/.django ./.envs/.local
cp -a ./docs/sample_envs/local/.postgres ./.envs/.local

编辑 .django.postgres 配置文件,包括您的 OpenAI API 密钥,并为数据库用户设置一个唯一密码。您还可以在 .django 文件中设置响应令牌限制或切换要使用的 OpenAI 模型。假设您有权限访问,GPT4 受支持。

使用 --profiles fullstack 标志构建 Docker Compose 堆栈:

sudo docker-compose --profiles fullstack -f local.yml build

fullstack 标志指示 compose 从前端文件夹构建一个 Docker 容器,并将其与所有需要的后端容器一起启动。然而,构建生产 React 容器需要很长时间,因此我们不建议您以这种方式进行开发。请按照项目 readme.md 中的说明进行开发环境设置说明。

最后,启动应用程序:

sudo docker-compose -f local.yml up

现在,在浏览器中访问 localhost:3000,即可查看前端,并在本地使用 Delphic 应用程序。

使用应用程序#

设置用户#

为了实际使用应用程序(目前,我们打算使与未经身份验证的用户共享某些模型成为可能),您需要登录。您可以使用超级用户或非超级用户。在任何情况下,首先需要有人使用控制台创建一个超级用户:

为什么要设置 Django 超级用户? Django 超级用户在应用程序中拥有所有权限,可以管理系统的所有方面,包括创建、修改和删除用户、集合和其他数据。设置超级用户允许您完全控制和管理应用程序。

如何创建 Django 超级用户:

1 运行以下命令创建超级用户:

sudo docker-compose -f local.yml run django python manage.py createsuperuser

2 您将被提示提供超级用户的用户名、电子邮件地址和密码。输入所需信息。

如何使用 Django 管理员创建其他用户:

  1. 根据部署说明在本地启动您的 Delphic 应用程序。
  2. 通过浏览器访问 http://localhost:8000/admin 进入 Django 管理界面。
  3. 使用您之前创建的超级用户凭据登录。
  4. 在“认证和授权”部分下点击“用户”。
  5. 在右上角点击“添加用户 +”按钮。
  6. 输入新用户的必要信息,如用户名和密码。点击“保存”以创建用户。
  7. 要为新用户授予额外权限或使其成为超级用户,请点击用户列表中的用户名,滚动到“权限”部分,并相应配置其权限。保存更改。