conversationsService.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { Conversation } from "../models/Conversation.model.js";
  2. import { Message } from "../models/Message.model.js";
  3. export async function listConversations(userId, { limit = 50, offset = 0 } = {}) {
  4. const safeLimit = Math.min(Number(limit) || 50, 100);
  5. const safeOffset = Math.max(Number(offset) || 0, 0);
  6. return Conversation.query()
  7. .where({ UsuarioId: userId })
  8. .orderBy("UpdatedAt", "desc")
  9. .limit(safeLimit)
  10. .offset(safeOffset)
  11. .select("Id", "Title", "CreatedAt", "UpdatedAt")
  12. .select(Conversation.relatedQuery("messages").count().as("MessageCount"));
  13. }
  14. export async function createConversation(userId, title = "Nova conversa") {
  15. const conv = await Conversation.query().insert({
  16. UsuarioId: userId,
  17. Title: String(title).slice(0, 255)
  18. });
  19. return { id: conv.Id, title };
  20. }
  21. export async function getConversationMessages(conversationId, userId) {
  22. const conv = await Conversation.query().findOne({ Id: conversationId, UsuarioId: userId });
  23. if (!conv) return null;
  24. const msgs = await Message.query()
  25. .where({ ConversationId: conversationId })
  26. .orderBy("SentAt", "asc")
  27. .select("Id", "Role", "Content", "Sources", "SentAt");
  28. return msgs;
  29. }
  30. export async function verifyConversationOwner(conversationId, userId) {
  31. const conv = await Conversation.query().findOne({ Id: conversationId, UsuarioId: userId });
  32. return Boolean(conv);
  33. }
  34. export async function getRecentMessages(conversationId, userId, limit = 12) {
  35. if (userId) {
  36. const owns = await verifyConversationOwner(conversationId, userId);
  37. if (!owns) return [];
  38. }
  39. const msgs = await Message.query()
  40. .where({ ConversationId: conversationId })
  41. .orderBy("SentAt", "desc")
  42. .limit(limit)
  43. .select("Role", "Content");
  44. return msgs.reverse();
  45. }
  46. export async function addMessage(conversationId, { role, content, sources = null }) {
  47. await Conversation.transaction(async (trx) => {
  48. await Message.query(trx).insert({
  49. ConversationId: conversationId,
  50. Role: role,
  51. Content: content,
  52. Sources: sources ? JSON.stringify(sources) : null
  53. });
  54. await Conversation.query(trx)
  55. .patch({ UpdatedAt: trx.fn.now() })
  56. .where({ Id: conversationId });
  57. });
  58. }
  59. export async function updateConversationTitle(conversationId, userId, title) {
  60. await Conversation.query()
  61. .patch({ Title: String(title).slice(0, 255), UpdatedAt: Conversation.knex().fn.now() })
  62. .where({ Id: conversationId, UsuarioId: userId });
  63. }
  64. export async function deleteConversation(conversationId, userId) {
  65. await Conversation.query().delete().where({ Id: conversationId, UsuarioId: userId });
  66. }
  67. export async function getConversationForExport(conversationId, userId) {
  68. const conv = await Conversation.query().findOne({ Id: conversationId, UsuarioId: userId });
  69. if (!conv) return null;
  70. const msgs = await Message.query()
  71. .where({ ConversationId: conversationId })
  72. .orderBy("SentAt", "asc")
  73. .select("Role", "Content", "SentAt");
  74. return { title: conv.Title, createdAt: conv.CreatedAt, messages: msgs };
  75. }
  76. export async function exportConversationAsMarkdown(conversationId, userId) {
  77. const data = await getConversationForExport(conversationId, userId);
  78. if (!data) return null;
  79. const date = new Date(data.createdAt).toLocaleDateString("pt-BR", {
  80. day: "2-digit", month: "2-digit", year: "numeric"
  81. });
  82. const lines = [`# ${data.title}`, `*Exportado em ${date}*`, ""];
  83. for (const msg of data.messages) {
  84. const author = msg.Role === "user" ? "**Você**" : "**Oráculo**";
  85. lines.push(`${author}:`, "", msg.Content, "");
  86. lines.push("---", "");
  87. }
  88. return lines.join("\n");
  89. }