Angular HttpClient:如何在不等待完整结果的情况下部分读取流响应?

Alv*_*nus 9 javascript node.js angular

因此,我尝试从 NodeJS 服务器读取 Chat GPT API 响应。响应从我的后端通过管道传输到客户端(在 Angular 中)。

const chatStream = await fetch("https://api.openai.com/v1/chat/completions", {
  method: "POST",
  body: JSON.stringify({
    model: process.env.CHAT_GPT_MODEL,
    messages,
    n: 1,
    max_tokens: parseInt(process.env.CHAT_GPT_TOKEN_LIMIT ?? "2000"),
    stream: true,
  }),
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer " + process.env.CHAT_GPT_API_KEY,
  },
});

res.setHeader("Content-Type", "application/octet-stream");
res.setHeader(
    "Content-Disposition",
    'attachment; filename="generated_text.txt"'
);

// Pipe the GPT API response directly to the client's response object
chatStream.body.pipe(res);
Run Code Online (Sandbox Code Playgroud)

这就是我在前端(Angular)处理响应的方式。这是我的httpPostStream功能:

  const res = this.http
    .post(this.getUrl(url), body, {
      headers: {
        'Content-Type': 'application/json',
        // eslint-disable-next-line quote-props
        Authorization: 'Bearer ' + this.auth?.loginToken,
      },
      responseType: 'blob',
      observe: 'body'
    })
    .pipe(catchError(this.catchError.bind(this)));
Run Code Online (Sandbox Code Playgroud)

并由此被调用:

const res = this.http
  .httpPostStream('/create-new-chat-gpt-room', { title })
  .subscribe((result: any) => {
    const reader = new FileReader();
    reader.onload = () => {
      const text = reader.result as string;
      const parts = text.split('\n'); // Split text into parts based on newline character
      for (const part of parts) {
        // Display each part as needed
        console.log(part);
      }
    };
    reader.readAsText(result);
  });
Run Code Online (Sandbox Code Playgroud)

问题是console.log(part)只有在结果fully返回后才运行。我想尽快记录每个部分,因为结果是逐部分返回的,我不想等到完成Blob

我怎样才能做到这一点?

Mar*_*ijk 2

这可以用 Angular 的法线来完成HttpClient。您需要以下方法来实现这一点。

\n

在您进行调用main.ts的地方,让 HttpClient 使用HttpFetchBackend,以便用于所有 HTTP 请求。bootstrapApplicationwithFetchfetch

\n
bootstrapApplication(AppComponent, {\n  providers: [\n    provideHttpClient(withFetch()),\n    // ...\n
Run Code Online (Sandbox Code Playgroud)\n

您现在可以使用 HttpClient 进行流式响应,但需要使用以下选项:

\n
{\n  observe: "events",\n  responseType: "text",\n  reportProgress: true\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以HttpEvent在响应流中获取 s,您可以检查其类型并进行处理。

\n
export default class ChatComponent {\n  currentUserMessage: string;\n  chatMessages: ChatMessage[];\n  loadingResponse: boolean = false;\n\n  sendMessage() {\n    if (this.currentUserMessage.trim() === "") return;\n\n    this.loadingResponse = true;\n    this.chatMessages.push({ role: "user", content: this.currentUserMessage});\n    this.currentUserMessage= "";\n    const responseMessage = {\n      role: "assistant",\n      content: "\xe2\x80\xa6",\n    };\n    this.chatMessages.push(responseMessage);\n\n    this.http\n      .post("/api/chat-gpt", this.chatMessages, {\n        observe: "events",\n        responseType: "text",\n        reportProgress: true,\n      })\n      .subscribe({\n        next: (event: HttpEvent<string>) => {\n          if (event.type === HttpEventType.DownloadProgress) {\n            responseMessage.content = (\n              event as HttpDownloadProgressEvent\n            ).partialText + "\xe2\x80\xa6";\n          } else if (event.type === HttpEventType.Response) {\n            responseMessage.content = event.body;\n            this.loadingResponse = false;\n          }\n        },\n        error: () => {\n          this.loadingResponse = false;\n        },\n      });\n  }\n\n
Run Code Online (Sandbox Code Playgroud)\n