chat.js 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { Router } from "express";
  2. import { z } from "zod";
  3. import { answerWithContext, answerWithContextStream } from "../../chat/chatChain.js";
  4. import { addMessage } from "../services/conversationsService.js";
  5. export const chatRouter = Router();
  6. const chatBodySchema = z.object({
  7. message: z.string().min(1),
  8. conversationId: z.coerce.number().int().positive().optional(),
  9. sessionId: z.string().min(1).optional(),
  10. model: z.string().min(1).optional(),
  11. options: z
  12. .object({
  13. temperature: z.number().min(0).max(2).optional(),
  14. top_p: z.number().min(0).max(1).optional()
  15. })
  16. .optional()
  17. });
  18. chatRouter.post("/", async (req, res, next) => {
  19. try {
  20. const body = chatBodySchema.parse(req.body);
  21. const result = await answerWithContext({
  22. message: body.message,
  23. conversationId: body.conversationId,
  24. options: body.options
  25. });
  26. const userId = req.user?.sub;
  27. if (userId && body.conversationId) {
  28. try {
  29. await Promise.all([
  30. addMessage(body.conversationId, { role: "user", content: body.message }),
  31. addMessage(body.conversationId, { role: "assistant", content: result.answer, sources: result.sources })
  32. ]);
  33. } catch (err) {
  34. console.error("[chat] falha ao salvar mensagem:", err);
  35. }
  36. }
  37. res.json(result);
  38. } catch (err) {
  39. next(err);
  40. }
  41. });
  42. chatRouter.post("/stream", async (req, res, next) => {
  43. let abortController;
  44. try {
  45. const body = chatBodySchema.parse(req.body);
  46. res.setHeader("Content-Type", "text/event-stream");
  47. res.setHeader("Cache-Control", "no-cache");
  48. res.setHeader("Connection", "keep-alive");
  49. res.setHeader("X-Accel-Buffering", "no");
  50. res.flushHeaders();
  51. abortController = new AbortController();
  52. res.on("close", () => abortController.abort());
  53. const result = await answerWithContextStream({
  54. message: body.message,
  55. conversationId: body.conversationId,
  56. options: body.options,
  57. signal: abortController.signal,
  58. onChunk: (delta) => {
  59. res.write(`data: ${JSON.stringify({ type: "delta", delta })}\n\n`);
  60. }
  61. });
  62. res.write(`data: ${JSON.stringify({ type: "sources", sources: result.sources })}\n\n`);
  63. res.write("data: [DONE]\n\n");
  64. res.end();
  65. const userId = req.user?.sub;
  66. if (userId && body.conversationId) {
  67. Promise.all([
  68. addMessage(body.conversationId, { role: "user", content: body.message }),
  69. addMessage(body.conversationId, { role: "assistant", content: result.answer, sources: result.sources })
  70. ]).catch((err) => console.error("[chat] falha ao salvar mensagem:", err));
  71. }
  72. } catch (err) {
  73. if (!res.headersSent) {
  74. next(err);
  75. } else if (err.name !== "AbortError") {
  76. res.write(`data: ${JSON.stringify({ type: "error", error: err.message })}\n\n`);
  77. res.end();
  78. }
  79. }
  80. });