@fr-data-fabric/chatbot-api-nest 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/chatbot-api.module.d.ts +27 -0
  2. package/dist/chatbot-api.module.js +63 -0
  3. package/dist/chatbot-api.module.js.map +1 -0
  4. package/dist/domain/entities/ChatEntity.d.ts +11 -0
  5. package/dist/domain/entities/ChatEntity.js +3 -0
  6. package/dist/domain/entities/ChatEntity.js.map +1 -0
  7. package/dist/domain/entities/ChatSourceEntity.d.ts +6 -0
  8. package/dist/domain/entities/ChatSourceEntity.js +3 -0
  9. package/dist/domain/entities/ChatSourceEntity.js.map +1 -0
  10. package/dist/domain/entities/ChatTextContentEntity.d.ts +4 -0
  11. package/dist/domain/entities/ChatTextContentEntity.js +3 -0
  12. package/dist/domain/entities/ChatTextContentEntity.js.map +1 -0
  13. package/dist/domain/entities/ConversationEntity.d.ts +9 -0
  14. package/dist/domain/entities/ConversationEntity.js +3 -0
  15. package/dist/domain/entities/ConversationEntity.js.map +1 -0
  16. package/dist/domain/entities/DocumentEntity.d.ts +3 -0
  17. package/dist/domain/entities/DocumentEntity.js +3 -0
  18. package/dist/domain/entities/DocumentEntity.js.map +1 -0
  19. package/dist/domain/entities/ToolUseEntity.d.ts +6 -0
  20. package/dist/domain/entities/ToolUseEntity.js +3 -0
  21. package/dist/domain/entities/ToolUseEntity.js.map +1 -0
  22. package/dist/domain/entities/UserEntity.d.ts +3 -0
  23. package/dist/domain/entities/UserEntity.js +3 -0
  24. package/dist/domain/entities/UserEntity.js.map +1 -0
  25. package/dist/domain/interfaces/ChatRepository.d.ts +5 -0
  26. package/dist/domain/interfaces/ChatRepository.js +5 -0
  27. package/dist/domain/interfaces/ChatRepository.js.map +1 -0
  28. package/dist/domain/interfaces/ConversationRepository.d.ts +6 -0
  29. package/dist/domain/interfaces/ConversationRepository.js +5 -0
  30. package/dist/domain/interfaces/ConversationRepository.js.map +1 -0
  31. package/dist/domain/interfaces/LLMService.d.ts +13 -0
  32. package/dist/domain/interfaces/LLMService.js +5 -0
  33. package/dist/domain/interfaces/LLMService.js.map +1 -0
  34. package/dist/domain/interfaces/PromptService.d.ts +8 -0
  35. package/dist/domain/interfaces/PromptService.js +5 -0
  36. package/dist/domain/interfaces/PromptService.js.map +1 -0
  37. package/dist/domain/use-cases/_common.d.ts +17 -0
  38. package/dist/domain/use-cases/_common.js +41 -0
  39. package/dist/domain/use-cases/_common.js.map +1 -0
  40. package/dist/domain/use-cases/chats/GetChatCompletionUC.d.ts +28 -0
  41. package/dist/domain/use-cases/chats/GetChatCompletionUC.js +83 -0
  42. package/dist/domain/use-cases/chats/GetChatCompletionUC.js.map +1 -0
  43. package/dist/domain/use-cases/chats/SendChatUC.d.ts +35 -0
  44. package/dist/domain/use-cases/chats/SendChatUC.js +166 -0
  45. package/dist/domain/use-cases/chats/SendChatUC.js.map +1 -0
  46. package/dist/domain/use-cases/chats/chat.types.d.ts +54 -0
  47. package/dist/domain/use-cases/chats/chat.types.js +3 -0
  48. package/dist/domain/use-cases/chats/chat.types.js.map +1 -0
  49. package/dist/domain/use-cases/conversations/CreateConversationUC.d.ts +6 -0
  50. package/dist/domain/use-cases/conversations/CreateConversationUC.js +5 -0
  51. package/dist/domain/use-cases/conversations/CreateConversationUC.js.map +1 -0
  52. package/dist/domain/use-cases/conversations/DeleteConversationUC.d.ts +10 -0
  53. package/dist/domain/use-cases/conversations/DeleteConversationUC.js +41 -0
  54. package/dist/domain/use-cases/conversations/DeleteConversationUC.js.map +1 -0
  55. package/dist/domain/use-cases/conversations/GenerateConversationTitleUC.d.ts +18 -0
  56. package/dist/domain/use-cases/conversations/GenerateConversationTitleUC.js +80 -0
  57. package/dist/domain/use-cases/conversations/GenerateConversationTitleUC.js.map +1 -0
  58. package/dist/domain/use-cases/conversations/GetConversationUC.d.ts +10 -0
  59. package/dist/domain/use-cases/conversations/GetConversationUC.js +31 -0
  60. package/dist/domain/use-cases/conversations/GetConversationUC.js.map +1 -0
  61. package/dist/domain/use-cases/conversations/GetConversationsUC.d.ts +9 -0
  62. package/dist/domain/use-cases/conversations/GetConversationsUC.js +27 -0
  63. package/dist/domain/use-cases/conversations/GetConversationsUC.js.map +1 -0
  64. package/dist/domain/use-cases/conversations/UpdateConversationUC.d.ts +15 -0
  65. package/dist/domain/use-cases/conversations/UpdateConversationUC.js +74 -0
  66. package/dist/domain/use-cases/conversations/UpdateConversationUC.js.map +1 -0
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.js +18 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/inputs/controllers/ChatsController.d.ts +8 -0
  71. package/dist/inputs/controllers/ChatsController.js +62 -0
  72. package/dist/inputs/controllers/ChatsController.js.map +1 -0
  73. package/dist/inputs/controllers/_common/CurrentUserRest.d.ts +1 -0
  74. package/dist/inputs/controllers/_common/CurrentUserRest.js +9 -0
  75. package/dist/inputs/controllers/_common/CurrentUserRest.js.map +1 -0
  76. package/dist/inputs/resolvers/ChatsResolver.d.ts +9 -0
  77. package/dist/inputs/resolvers/ChatsResolver.js +57 -0
  78. package/dist/inputs/resolvers/ChatsResolver.js.map +1 -0
  79. package/dist/inputs/resolvers/ConversationsResolver.d.ts +34 -0
  80. package/dist/inputs/resolvers/ConversationsResolver.js +170 -0
  81. package/dist/inputs/resolvers/ConversationsResolver.js.map +1 -0
  82. package/dist/inputs/resolvers/_common/CurrentUserGql.d.ts +1 -0
  83. package/dist/inputs/resolvers/_common/CurrentUserGql.js +10 -0
  84. package/dist/inputs/resolvers/_common/CurrentUserGql.js.map +1 -0
  85. package/dist/inputs/resolvers/_common/GqlPaginatedOutput.d.ts +8 -0
  86. package/dist/inputs/resolvers/_common/GqlPaginatedOutput.js +37 -0
  87. package/dist/inputs/resolvers/_common/GqlPaginatedOutput.js.map +1 -0
  88. package/dist/tsconfig.tsbuildinfo +1 -0
  89. package/docs/entities.excalidraw.svg +2 -0
  90. package/package.json +25 -0
  91. package/src/chatbot-api.module.ts +90 -0
  92. package/src/domain/entities/ChatEntity.ts +13 -0
  93. package/src/domain/entities/ChatSourceEntity.ts +6 -0
  94. package/src/domain/entities/ChatTextContentEntity.ts +4 -0
  95. package/src/domain/entities/ConversationEntity.ts +10 -0
  96. package/src/domain/entities/DocumentEntity.ts +3 -0
  97. package/src/domain/entities/ToolUseEntity.ts +6 -0
  98. package/src/domain/entities/UserEntity.ts +3 -0
  99. package/src/domain/interfaces/ChatRepository.ts +7 -0
  100. package/src/domain/interfaces/ConversationRepository.ts +8 -0
  101. package/src/domain/interfaces/LLMService.ts +15 -0
  102. package/src/domain/interfaces/PromptService.ts +10 -0
  103. package/src/domain/use-cases/_common.ts +28 -0
  104. package/src/domain/use-cases/chats/GetChatCompletionUC.ts +126 -0
  105. package/src/domain/use-cases/chats/SendChatUC.ts +202 -0
  106. package/src/domain/use-cases/chats/chat.types.ts +51 -0
  107. package/src/domain/use-cases/conversations/CreateConversationUC.ts +7 -0
  108. package/src/domain/use-cases/conversations/DeleteConversationUC.ts +29 -0
  109. package/src/domain/use-cases/conversations/GenerateConversationTitleUC.ts +69 -0
  110. package/src/domain/use-cases/conversations/GetConversationUC.ts +18 -0
  111. package/src/domain/use-cases/conversations/GetConversationsUC.ts +21 -0
  112. package/src/domain/use-cases/conversations/UpdateConversationUC.ts +54 -0
  113. package/src/index.ts +1 -0
  114. package/src/inputs/controllers/ChatsController.ts +47 -0
  115. package/src/inputs/controllers/_common/CurrentUserRest.ts +10 -0
  116. package/src/inputs/resolvers/ChatsResolver.ts +40 -0
  117. package/src/inputs/resolvers/ConversationsResolver.ts +149 -0
  118. package/src/inputs/resolvers/_common/CurrentUserGql.ts +11 -0
  119. package/src/inputs/resolvers/_common/GqlPaginatedOutput.ts +25 -0
  120. package/tsconfig.json +28 -0
@@ -0,0 +1,2 @@
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 974.9219433561672 517.9100564954243" width="974.9219433561672" height="517.9100564954243"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1cXGtT28hcdTAwMTL9nl9BsV+X2Xk/turWrfBOQthcXFxmXHUwMDAxcmuLki1hXHUwMDA0suTIMq+t/PfbI4MlWbLwQ1x1MDAxYqi9XHUwMDE2XHUwMDE1YkZjqTXTffp0T4/+ere2tp489L3139fWvfuOXHUwMDEz+G7s3K3/attvvXjgRyGcounfg2hcdTAwMTh30p5XSdJcdTAwMWb8/ttvPSe+8ZJ+4HQ8dOtcdTAwMGaGTjBIhq5cdTAwMWahTtT7zU+83uDf9veh0/P+1Y96blx1MDAxMqPsJlx1MDAxYp7rJ1E8updcdTAwMTd4PS9MXHUwMDA2cPX/wt9ra3+lv+GM79o7XrPBMDr4tHnaXHSH0fvj/Z5+/9hPv5p2en6E2OskTthccrzs1D20c4yM1EqMXHUwMDFiXHUwMDFmoJFcdTAwMTCDeKH1zneTK3tGSGRcYseSZueuPL97lcBJrVx1MDAxMVNcdTAwMDRcdTAwMWKW++Lolr+v4XHLIImjXHUwMDFibytcbuBcdTAwMDFBrl+IZ38yqdpO56ZcdTAwMWJHw9BcdTAwMWT3SWInXHUwMDFj9J1cdTAwMTiGIet36Vx1MDAwN0EreUivXHUwMDBlXHUwMDEzXHUwMDAwI7c+cY/TJ6HpRPu0b8FNu1ehN7BDTcatUd/p+Ek6LDh7XG4rYf+Dm87Kn5lMMcznXHUwMDA3Oy3hMFxixs1+6Hp2sNdcdTAwMWRcXLhb6D7d7XlKs/liTy0/Mtk9z16YcMWkXHUwMDE2ipnxmUxcdTAwMWJcdTAwMTWZbDyMwlQxiTSMY6Nl1sNcdTAwMWZsg24l6VUvQT+9bFxurGg7k3qX172CaiXefTYvOc287LViqXcuOrdOn1x1MDAxOP24L1x1MDAwZj6r9XG/XHUwMDFmv1ZfdvTlrU+PXHUwMDFi3v5dvP949yH+XHUwMDEysXOvu+dcdTAwMTbv8nx/J46ju1mvS1x1MDAwNTndOaAnZ49H/WPmeqePcbw323WfPmXTPey7zmj8iFJcZktuXHUwMDE05TJT/sBcdTAwMGZvJnUhiDo32ZC/y1x0PGHX1aNXsuvC4KcmLSXCSmiKXHKlWoDFXHUwMDE2bVtcdTAwMTBEXHUwMDA0p6bavrFE0lx1MDAxOEOxXHUwMDFj9dFlM6cr655i3aTaulx1MDAwYr0zM9ZGXHUwMDBiplWFXHUwMDE5czzNjLmSnFNh1FwiVlxcp7iCMUbnUNxMXHUwMDBmrf7Bw59cZrx4J0zsWGZcdTAwMDNcdTAwMTaFSct/tIJTXFxo3XV6fmBHXVx1MDAxNC70PvC7dlx1MDAwMNY7ILNcdTAwMTev54ch8cE9jjv0fNfN+7JcdTAwMGVcXNTxQy/+MItTjGK/64dOcFxcI7wzTKIjbzBcdTAwMTI/iYdefnS8/WdrIIiKXHUwMDFhK35I9Ie9vW/hYVx1MDAxOHe/J8fnnePuoD2zd2aCopKtjjy0QlxuK8xcYi1cdTAwMWIxJVxmhFKaUG7SI9OWla+e3Zrp8r6aXHUwMDExYYgyRuRcdTAwMTX5mTlcdTAwMTI62Tp21lx1MDAwMFxmWGBMXHUwMDE3MvM673d7dD38utuSXHUwMDE3305p0L482dzqXHUwMDFkJdXeLzXsV3bW5MZptduf7rzbXHUwMDAzL/I2zVXX71x1MDAxYzbjrFx1MDAwNdXaSKnzVr24s65cdTAwMWbXXHUwMDFhZ82kQIxcdTAwMTHDjFx1MDAwNPIgJ501N4iZkS1XOGutkFRGKyyxKPL1lbN+0bzZ7M6aXG6tXHUwMDAwTFx1MDAwNasyY8ynmjHnXHUwMDE2olx1MDAwNVuIc9dpLoRcdTAwMDCSz6G5JW+9XHUwMDE1hVZYJ1x1MDAwMXHfjtd+wVlOeu26h2jGe5v9a1CYmyvv/qwz7EahXHUwMDE3/seP5vDeXG6st1x1MDAxMCvbwWOMIzyNgK98dzPGvbe08+ZAvFx1MDAxNJe0Ks6mqkTbM99cckbKpZJcdTAwMTlYNOS7b9R5t/3ofTy7fO9u9Fx1MDAxY3Z0cHz2/Vx1MDAxZum76+V1qffx6MLf3rre3P18+8lt6++dXHUwMDA2rvux/UfrobXT0ye9h5ZqXHUwMDA1f3zzt1x1MDAwZlx1MDAxYbju15a/qTc/t1xc/+zguLN3dbj/pXvawHXdc1x1MDAxM3ei/eD8ZjtUiTpsbSa9b40lMqiE/5vhRvV6W8ONODZIMiMkXHUwMDE3hFx1MDAxM4lJkVx1MDAxY1nqpEZcdTAwMTmOKnKENVLCXHUwMDE4QFtFgCXJzI5X5Ohl/Pw6OztiTGBccupSyj2mQCknW5+Bklx1MDAxYVx1MDAwZXPLcLOpXGZL623EvFx1MDAxNDm6cpK3Q4pe4CAlUlQhfDNk6Dqmg3b//JPT3eYqMLJcdTAwMWR/+HgxM1x1MDAxOYLQXHUwMDA2SYrBMVx1MDAxYYJcdGVFTiSoQkCwwVxcIVjmlGfOc0WMmjVsd2liXHUwMDA0XGZcdTAwMDdcdTAwMGKpqalcboc4nZq7JFx1MDAwMNacwVx1MDAwNDbOjPbuNr58XHUwMDEx7934/Hoj2L9q3/ne9tb/XHUwMDFmM1qCaczAXGJcdTAwMDQnVOaBY3FGUD9fdUtcdTAwMWJKWkYgOVx1MDAxM1x1MDAxYTiKzlxmK1x1MDAwNVx1MDAxMaGRYURwrFx1MDAxNa5cdTAwMDRcdTAwMTGiXHUwMDAwRIjRylx1MDAxMIHT0GxFXG7mwI5gjvVcco0x5lrxyvVccl6CjjFIXGJuOJXgxFx1MDAxYqVcdTAwMDVcdTAwMGLobyUtaKVcdTAwMGL9b4dcdTAwMWO84JOryEH1IzRDXHUwMDExdvewd3l0tudcdTAwMDT3R4c9Mbxpf9rbnz1fwjRcdTAwMDKij1x0XHUwMDAxXHUwMDFlR0huMXtEXHUwMDExKMKcK62A8tslyjJFUFx1MDAxOGEpKCaKY2FE9v1cdTAwMTVDmMPK+0szXHUwMDA0xSnRXFzoqohA1Fx1MDAxMFx1MDAwNKMoXHUwMDA0cyZX2tBcdTAwMTBBXHUwMDEwe3Hs4HjLPTi/oI/e7nb7Yefj/1x1MDAxZkFYXCLF8XNcdEL9fNUtp1xijowtkGHaXHUwMDAw32STXHUwMDA0gSGQ1aZcdTAwMDSorIZcdTAwMTAmXHUwMDExhCBaQLiimKar8od5kCOZg1x1MDAxZkhpwNJcdTAwMDWpWlx1MDAxYVx1MDAxNblluVx0jGCKa5lPyr4ldmDd7Fx1MDAxNjhouOHboVxiL/jkKopQ81x1MDAxY83whHvqbZzuuOF3b+fj3mW/dXpyfyxn5lx0lCBBKFx1MDAwNZZANFx1MDAxOLI0mbaMiFx1MDAwMkNCXHUwMDFiwzSjXHUwMDAygoFMV1ZEoVFzv10+lSAol0zDJFShgJ7OXHUwMDE0XHUwMDE4XHUwMDA0gIDyvPFUwt1cdTAwMTeKXHUwMDA332RwcVx1MDAxNXhn/autx+RhMCWG/iczhSVcdTAwMTZZfi5TqJ+vXHUwMDFhpqBcdTAwMDU4eq5cdTAwMDVEXHUwMDFhXHUwMDEwcEwgiFx1MDAxMIgqXHUwMDAxZynGlVxiQjhF1DJcYqkmijNWPOFl4LifgyfAXFxohlVlXHSV5NPrnVx1MDAwMVx1MDAxZShjXHUwMDEyv708wnFcdTAwMTRcdTAwMDUngzeURHjBXHUwMDFiTzKEKfI3w1xmnK/fXHUwMDFm4oODLexcdTAwMThcdTAwMTleXHUwMDA3XHUwMDA3vHu4tT0zM9hcdTAwMDCrxpxxXHUwMDAxpi3hg5xYMVx1MDAwNHbPXHIhQilQXHUwMDBlzHVF/cWKXHUwMDFhNGHhXHUwMDBmS1NcdTAwMDOKtV0voLIqiVCRVlx1MDAxY1x1MDAxYj7lgOlK4Vx1MDAwNjc6jFTzw4nX3yXhKf78+eL2cJdccoPecW9FXHKaqr9Yop6h9rp/84ZcdTAwMGal56rEq4G+ev2qoTJcdTAwMWJUXHUwMDAzqGJcclRGMsI158W0XHUwMDA3XHUwMDEwZUSUVFx1MDAxOLi2qoY9u6+LK2MwXHUwMDA33NOYVyyurvjMVLR7nGtdRFMgXHUwMDExlXlcdTAwMGZNSsVm42pcdKBBhoqF4p0m9bfEZrajzrD3plx1MDAxMlx1MDAxZS9QiEk6M+1cdTAwMDGa4TP16D6BPFx1MDAwNaumXHUwMDE4QlxmWy2hKVbMsInKcElcdTAwMTBEzmCwhjBcdTAwMDFcXCWz2CxGIUhLI4mGf/BTudiJlNZg84xcdTAwMDMyMJbLq61svGDjfFZCQ6dcdTAwMTFcdTAwMWFcclx1MDAxM2Er2apcdTAwMTZExfRcdTAwMWFymH+lIeZoPuNcdPPN8jo9q+X3I3+SLWWf1jKFSf9cdTAwMTh//vPXyt7TldRcdTAwMWVcdTAwMWIl/cyuV3LOgTNItqJez0/gQb9YIUtcdTAwMTicOHGyXHST6ofd4uQ9bbKeZfNYimKdoVx1MDAxZIBccohcdTAwMTWw5lx1MDAxMihcdTAwMDbYKIFoXHUwMDEzZ1x1MDAxOSmra07fTi5cIjitUSxphlx1MDAxN7ovS1NfXHUwMDE0n5NcdTAwMDYjQrhQhmtcdTAwMDZ4oCFwJiVZXGaiXHUwMDEwXHUwMDE42dClrKZ2cN5bXHUwMDFjuvKckiWAqPlzk4DlXHUwMDA17ehuJpZTT0vrXHUwMDAwkVx1MDAwM0cppFpcdTAwMWVSlDRIc1ZRSY+RLMZoY9AjhFwiXGJcdTAwMTHJitFMQzuxNNqBXHUwMDEwnGJcdTAwMTj+Kp4zvfxDUIkhgFusRKzJvV5/XHUwMDBm2k3qpD0ybfxcdTAwMTnYNlx1MDAwN5rYicBaMymoXU5ROtdrhCZcZim5OLDVXHUwMDE3tk7ALEiAMVx1MDAwNaVSwiiJyyhLXGJSr1xmbfWRcT20XHUwMDE5JJikXG5cdTAwMTRBccZy20usRXMqXHUwMDExPJlUtjZcbixEVpTHXG7gg3BcdTAwMDJcdTAwMTSdcqK5rojgjFx1MDAwMHeFIcijYFx1MDAxNErleP9cbv5cbvAnl4Y/iMPTnfpVZI9Mj/LgO1x1MDAxMJ4vuKz1UtI6k+W14G9jupbao6SfP1x1MDAwM1x1MDAxMOdBIWH3dUkuhaZcdTAwMDb4s8z1XHUwMDFhgZBcdTAwMDaCoiGKZ0IyXHUwMDA2XHUwMDFky/oxXHUwMDEzMtYn5IsyUS1B2Vx1MDAxOIBcIswxkNGSTFxuXHUwMDAxccZcdTAwMThgXFxJXHUwMDAyykVeXHUwMDBiXHUwMDFl66uP6uGRXHUwMDAzb6Uw4spuXHUwMDFkUJn9PKMjtVx1MDAxYoEkgCM4KlxcxVx1MDAwNTFWWlx0XHUwMDA2XHUwMDExXHUwMDE451x1MDAxNklNXHUwMDA2flx1MDAxOT5ipFx1MDAxOGVwLWZLXHUwMDBi9IpcdTAwMWVOwUe1PD1cdTAwMTSWXHUwMDFickyrsvvld6I846OmXHUwMDFjS81E868/eVx1MDAxM/hYp6b2KCnom1x1MDAwMkiQ3tbcXHUwMDAxQaOG4dRSq+JPXHUwMDAyXHUwMDA0XHUwMDA3ZFf2ZVRiQepYX9NUXHUwMDA0SMIxwZRcdTAwMDF9XHUwMDA06DbElFx1MDAxMZIwpG1eXHUwMDFjOkpcdTAwMThzgPfXgsj6XHUwMDFkXHUwMDFjtVx1MDAxMMk1UopcdTAwMDJAXHUwMDFhrJQhvFx1MDAxOCZcdTAwMDNcdTAwMTOxXFxcdTAwMWRcXKtNXCLzXHUwMDFj9Vx1MDAxYlx1MDAxM0jNkV1rXHUwMDA3U7AlkiSjIFx1MDAxOT5ypIyCu2iwQ65zXHUwMDA2s8LHXHUwMDAyPuql8ZFcdTAwMDJccqLFvVI5fJxaXHUwMDFkXHSQapSRi7035u3j41RcdTAwMWS1R0k731x1MDAxODhKW01kN6eCgWrMTa7TXHUwMDEzXGbZPIBJV9+wjVx1MDAxZipcdTAwMDLZmcCxfk9IQSagg1x1MDAxOFxipMJcdTAwMTazhSlcdTAwMTNaiKoxpcDHMdPMXGLC5WtBY/3ycFx1MDAxZDQyrpCt5aBcdTAwMTBcXFxixnLBVbo4qlxmUlx1MDAwMjCfXHRBwLlWsEdcIijSXHUwMDFhZkRcdTAwMThcIoHd01xubCRIwFhcbsXs5jNcIvP4u1x1MDAwMsdcdTAwMDI4muXJo7aRjE0vVoAjZzWv1cLSUIJcdTAwMTd7XHUwMDA35kurqPO89vFvXG6vpyuqPcoq+qZcdTAwMTDSZvlcYubS7lxuwERcdTAwMTFcdTAwMThRU5nmXHUwMDAzXHUwMDBlwzU8XHUwMDFiXHUwMDAxp6R0mavNXHUwMDA0kvWLxEVWK1xigehTXHUwMDAzjmjMhFZcdTAwMTVcZtLSTFx1MDAwZf20XHUwMDAyXHUwMDA1XHUwMDAznK/Q3Z9cdTAwMDOT9dUudTBJgFx1MDAwNkubZyWcWCicqImlRFwiXHUwMDA15k+0YdxwnDmLMU5KbFx1MDAwYuOUsFXdQnFeufTCXHUwMDExp1xccWJcZpgjy+0hX8FkXHUwMDAxJjeb4JBcdTAwMTjUUZdXW9LpnE5cIlxyWCBcdTAwMDBb40lIbV969fooOVVN7VFW0J9cdTAwMDGS86w4Q1x1MDAwMK1cdTAwMTU1miiIWFx0za2XZ0lIXGK+4fn0yE5cdTAwMTdMQs6MkFx1MDAxYiPws2lP8CpcdTAwMDRoLisjpEA2J2ps8kZcYmNkRd1n41x1MDAwMPnuaa7WnX6/lYAyjp9cdTAwMTaM0ncnqpNGbYmXSptr+lx1MDAxY7neTui0g0nFXFy/9b27zTJcdTAwMDb9cplcdTAwMWW2jjB9Oos/Xmq7P979+Fx1MDAxZtUxXHUwMDA3XG4ifQ==<!-- payload-end --></metadata><defs><style class="style-fonts">
2
+ @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }</style></defs><rect x="0" y="0" width="974.9219433561672" height="517.9100564954243" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(136.01220394604366 11.76171875) rotate(0 78.45703125 44.185546875)"><path d="M22.09 0 C55.43 -1.61, 87.71 1.6, 134.82 0 M22.09 0 C57.99 0.1, 94.45 -0.83, 134.82 0 M134.82 0 C149.8 1.13, 155.86 8.7, 156.91 22.09 M134.82 0 C150.86 -2.25, 158.5 8.9, 156.91 22.09 M156.91 22.09 C158.44 30.23, 155.09 41.37, 156.91 66.28 M156.91 22.09 C157.89 38.01, 156.75 54.25, 156.91 66.28 M156.91 66.28 C156.18 80.6, 149.73 86.77, 134.82 88.37 M156.91 66.28 C156.95 81.41, 149.09 89.24, 134.82 88.37 M134.82 88.37 C100.11 87.95, 64.59 87.56, 22.09 88.37 M134.82 88.37 C110.98 87.57, 88.97 89.08, 22.09 88.37 M22.09 88.37 C9.31 88.48, -1.47 79.72, 0 66.28 M22.09 88.37 C6.2 86.94, -1.7 80.56, 0 66.28 M0 66.28 C0.72 56.01, -1.95 42.58, 0 22.09 M0 66.28 C-0.62 55.9, -0.12 46.89, 0 22.09 M0 22.09 C1.43 8.65, 7.25 1.85, 22.09 0 M0 22.09 C0.83 5.94, 7.05 0.27, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(161.11927486889522 43.447265625) rotate(0 53.34996032714844 12.5)"><text x="53.34996032714844" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">UserEntity</text></g><g stroke-linecap="round" transform="translate(447.58642269604366 10) rotate(0 106.62890625 44.185546875)"><path d="M22.09 0 C61.29 1.86, 99.16 0.32, 191.17 0 M22.09 0 C88.34 1.16, 155.02 1.18, 191.17 0 M191.17 0 C207.18 1.93, 211.62 6.08, 213.26 22.09 M191.17 0 C205.91 2.05, 214.51 8.93, 213.26 22.09 M213.26 22.09 C213.49 32.58, 215.68 40.53, 213.26 66.28 M213.26 22.09 C213.73 35.34, 213.43 47.61, 213.26 66.28 M213.26 66.28 C215.12 81.98, 206.49 86.83, 191.17 88.37 M213.26 66.28 C212.81 80.33, 205.17 90.56, 191.17 88.37 M191.17 88.37 C150.18 87.47, 106.04 86.74, 22.09 88.37 M191.17 88.37 C130.33 89.19, 69.55 89.84, 22.09 88.37 M22.09 88.37 C6.97 86.52, -1.96 82.88, 0 66.28 M22.09 88.37 C6.31 86.99, 1.15 82.9, 0 66.28 M0 66.28 C-0.63 55.24, 1.1 44.81, 0 22.09 M0 66.28 C-0.09 54.39, -0.03 43.3, 0 22.09 M0 22.09 C0.03 7.4, 8.69 -1.86, 22.09 0 M0 22.09 C-2.01 8.1, 8.57 -0.3, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(460.3753936433093 41.685546875) rotate(0 93.83993530273438 12.5)"><text x="93.83993530273438" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ConversationEntity</text></g><g stroke-linecap="round" transform="translate(452.43407894604366 226.3359375) rotate(0 106.62890625 44.185546875)"><path d="M22.09 0 C59.85 -0.83, 98.6 1.33, 191.17 0 M22.09 0 C64.78 -1.07, 106.06 -1.94, 191.17 0 M191.17 0 C205.75 1.83, 215.06 7.44, 213.26 22.09 M191.17 0 C206.8 1.17, 213.98 6.39, 213.26 22.09 M213.26 22.09 C211.21 37.24, 211.71 50.95, 213.26 66.28 M213.26 22.09 C213.6 37.4, 212.83 52.6, 213.26 66.28 M213.26 66.28 C211.55 82.29, 204.55 87.13, 191.17 88.37 M213.26 66.28 C214.74 82.48, 206.73 89.1, 191.17 88.37 M191.17 88.37 C150.78 87, 109.23 88.75, 22.09 88.37 M191.17 88.37 C129.95 89.06, 71.14 88.38, 22.09 88.37 M22.09 88.37 C5.51 88.98, 1 82.17, 0 66.28 M22.09 88.37 C6.78 86.4, 1.97 80.14, 0 66.28 M0 66.28 C-1.1 50.62, -1.9 32.3, 0 22.09 M0 66.28 C0.07 53.16, 1.31 41.75, 0 22.09 M0 22.09 C1.01 7.37, 8.23 -1.22, 22.09 0 M0 22.09 C-1.34 8.4, 8.96 1.5, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(504.6830184602038 258.021484375) rotate(0 54.379966735839844 12.5)"><text x="54.379966735839844" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ChatEntity</text></g><g stroke-linecap="round" transform="translate(751.6641308561672 419.5389627454243) rotate(0 106.62890625 44.185546875)"><path d="M22.09 0 C85.43 -1.51, 147.47 -2.31, 191.17 0 M22.09 0 C77.88 -0.43, 133.44 -0.93, 191.17 0 M191.17 0 C206.9 -0.53, 214.25 5.87, 213.26 22.09 M191.17 0 C206.83 0.8, 215.03 9.15, 213.26 22.09 M213.26 22.09 C213.51 34.52, 211.96 44.44, 213.26 66.28 M213.26 22.09 C212.62 33.25, 213.35 43.23, 213.26 66.28 M213.26 66.28 C214.77 81.79, 207.08 90.29, 191.17 88.37 M213.26 66.28 C211.26 79.04, 208 86.57, 191.17 88.37 M191.17 88.37 C153.92 89.68, 115.68 88.73, 22.09 88.37 M191.17 88.37 C133.07 88.91, 76.05 89.52, 22.09 88.37 M22.09 88.37 C7.67 86.98, 1.6 82.84, 0 66.28 M22.09 88.37 C5.56 88.56, 0.89 80.17, 0 66.28 M0 66.28 C0.81 53.24, 0 36.4, 0 22.09 M0 66.28 C0.42 55.43, -0.43 44.41, 0 22.09 M0 22.09 C1.51 9.29, 6.97 0.77, 22.09 0 M0 22.09 C-1.22 5.47, 8.67 -0.3, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(771.6830975309718 451.2245096204243) rotate(0 86.60993957519531 12.5)"><text x="86.60993957519531" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ChatSourceEntity</text></g><g stroke-linecap="round" transform="translate(433.18446525116076 414.3377566019992) rotate(0 135.03260087029759 44.185546875)"><path d="M22.09 0 C103.04 1.12, 181.2 0.01, 247.97 0 M22.09 0 C102.86 1.62, 183.66 2.14, 247.97 0 M247.97 0 C264.23 -0.57, 268.94 5.5, 270.07 22.09 M247.97 0 C260.8 1.13, 268.55 6.31, 270.07 22.09 M270.07 22.09 C269.77 33.04, 269.4 44.86, 270.07 66.28 M270.07 22.09 C270.2 38.85, 269.66 57.87, 270.07 66.28 M270.07 66.28 C270.59 79.97, 261.95 87.91, 247.97 88.37 M270.07 66.28 C270.97 81.37, 261.85 87.29, 247.97 88.37 M247.97 88.37 C201.07 87.98, 155.56 90.06, 22.09 88.37 M247.97 88.37 C170.77 87.49, 93.08 87.68, 22.09 88.37 M22.09 88.37 C7.27 88.56, 0.72 81.89, 0 66.28 M22.09 88.37 C7.46 86.23, -1.98 79.37, 0 66.28 M0 66.28 C0.99 52.81, -0.8 43.37, 0 22.09 M0 66.28 C0.1 57.9, -0.4 47.6, 0 22.09 M0 22.09 C-1.37 8.97, 7.7 -1.65, 22.09 0 M0 22.09 C0.35 5.49, 9.43 1.57, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(450.0171378377669 446.0233034769992) rotate(0 118.1999282836914 12.5)"><text x="118.1999282836914" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ChatTextContentEntity</text></g><g stroke-linecap="round" transform="translate(116.55566696477035 415.88290707554086) rotate(0 135.03260087029756 44.185546875)"><path d="M22.09 0 C99.65 0.77, 177.98 -0.33, 247.97 0 M22.09 0 C108.24 -0.38, 195.29 -0.61, 247.97 0 M247.97 0 C263.38 -1.78, 270.3 5.81, 270.07 22.09 M247.97 0 C262.62 -2.01, 268.94 8.33, 270.07 22.09 M270.07 22.09 C269.9 40.39, 270.18 56.03, 270.07 66.28 M270.07 22.09 C270.73 36.18, 270.21 50.37, 270.07 66.28 M270.07 66.28 C271.17 80.54, 262.08 89.9, 247.97 88.37 M270.07 66.28 C271.4 81.79, 262.35 86.34, 247.97 88.37 M247.97 88.37 C165.54 88.72, 80.66 90.92, 22.09 88.37 M247.97 88.37 C198.84 88.03, 147.24 88.36, 22.09 88.37 M22.09 88.37 C7.96 90.24, 0.03 79.22, 0 66.28 M22.09 88.37 C5.34 86.91, 1.47 82.02, 0 66.28 M0 66.28 C-0.02 55.12, 1.29 46.69, 0 22.09 M0 66.28 C-0.13 56.28, 0.06 47.98, 0 22.09 M0 22.09 C1.17 6.7, 7.28 0.68, 22.09 0 M0 22.09 C1.81 8.16, 9.42 1.44, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(180.43830445616166 447.56845395054086) rotate(0 71.14996337890625 12.5)"><text x="71.14996337890625" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ToolUseEntity</text></g><g stroke-linecap="round" transform="translate(10 228.78412651230485) rotate(0 135.03260087029756 44.185546875)"><path d="M22.09 0 C106.98 3.24, 188.68 1.21, 247.97 0 M22.09 0 C69.09 1, 116.57 0.18, 247.97 0 M247.97 0 C261.25 -0.12, 270.67 6.58, 270.07 22.09 M247.97 0 C264.68 -0.5, 270.71 7.13, 270.07 22.09 M270.07 22.09 C268.54 34.95, 270.88 46.06, 270.07 66.28 M270.07 22.09 C269.23 35.6, 269.37 48.57, 270.07 66.28 M270.07 66.28 C270.77 81.47, 261.68 87.34, 247.97 88.37 M270.07 66.28 C271.49 80.48, 261.03 87.99, 247.97 88.37 M247.97 88.37 C175.54 87.14, 103.19 88.12, 22.09 88.37 M247.97 88.37 C202.88 87.27, 155.56 87.48, 22.09 88.37 M22.09 88.37 C9.18 90.21, -0.14 80.35, 0 66.28 M22.09 88.37 C6.8 90.21, 1.25 82.01, 0 66.28 M0 66.28 C-2.08 55.28, -1.65 42.49, 0 22.09 M0 66.28 C-0.83 56.72, -0.59 47.32, 0 22.09 M0 22.09 C-1.3 5.48, 6.06 0.57, 22.09 0 M0 22.09 C1.84 7.52, 7.11 -2.23, 22.09 0" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(66.79264878289521 260.46967338730485) rotate(0 78.23995208740234 12.5)"><text x="78.23995208740234" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">DocumentEntity</text></g><g stroke-linecap="round"><g transform="translate(297.32037215343723 53.931873663574066) rotate(0 70.93480948080831 -1.3942086718666644)"><path d="M-0.08 -0.42 C23.31 -0.68, 117.74 -1.63, 141.39 -2.13 M-1.59 -1.68 C21.51 -2.25, 116.42 -3.79, 140.19 -3.91" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(297.32037215343723 53.931873663574066) rotate(0 70.93480948080831 -1.3942086718666644)"><path d="M116.8 4.91 C125.2 0.71, 136.04 -1.99, 140.19 -3.91 M116.8 4.91 C122.64 3.21, 127.46 1.37, 140.19 -3.91" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(297.32037215343723 53.931873663574066) rotate(0 70.93480948080831 -1.3942086718666644)"><path d="M116.6 -12.19 C125 -9.77, 135.91 -5.85, 140.19 -3.91 M116.6 -12.19 C122.66 -9.67, 127.53 -7.29, 140.19 -3.91" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(551.8559539460437 102.13671875) rotate(0 0.3046875 56.2265625)"><path d="M0.05 0.73 C0.03 19.73, -0.25 94.6, -0.29 113.33 M-1.38 0.07 C-1.01 18.8, 1.33 93.16, 1.95 111.67" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(551.8559539460437 102.13671875) rotate(0 0.3046875 56.2265625)"><path d="M-7.35 88.46 C-3.6 93.58, -0.71 100.4, 1.95 111.67 M-7.35 88.46 C-3.48 97.34, -0.27 105.75, 1.95 111.67" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(551.8559539460437 102.13671875) rotate(0 0.3046875 56.2265625)"><path d="M9.74 87.92 C8.6 93.2, 6.62 100.17, 1.95 111.67 M9.74 87.92 C7.53 97.16, 4.66 105.76, 1.95 111.67" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(554.5797284834774 318.38664369226063) rotate(0 -125.80319446209243 47.50049513868882)"><path d="M0.81 -0.7 C-41.03 15.33, -208.4 79.47, -250.43 95.44 M-0.22 1.55 C-42.18 17.28, -208.8 77.72, -250.76 93.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(554.5797284834774 318.38664369226063) rotate(0 -125.80319446209243 47.50049513868882)"><path d="M-231.68 77.39 C-239.67 85.16, -244.49 89.27, -250.76 93.54 M-231.68 77.39 C-236.71 82.42, -243.4 87.41, -250.76 93.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(554.5797284834774 318.38664369226063) rotate(0 -125.80319446209243 47.50049513868882)"><path d="M-225.76 93.43 C-235.73 95.6, -242.64 94.06, -250.76 93.54 M-225.76 93.43 C-232.51 93.48, -241.03 93.54, -250.76 93.54" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(549.2859906472816 318.56582517289905) rotate(0 0.003937693222468397 45.366163616509425)"><path d="M0.7 0.34 C0.82 15.61, 0.45 76.73, 0.22 91.77 M-0.39 -0.53 C-0.36 14.41, -0.38 74.81, -0.61 90.19" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(549.2859906472816 318.56582517289905) rotate(0 0.003937693222468397 45.366163616509425)"><path d="M-9 66.64 C-6.26 73.01, -2.93 77.58, -0.61 90.19 M-9 66.64 C-6.03 72.59, -5.04 80.46, -0.61 90.19" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(549.2859906472816 318.56582517289905) rotate(0 0.003937693222468397 45.366163616509425)"><path d="M8.1 66.76 C6.44 73.2, 5.37 77.73, -0.61 90.19 M8.1 66.76 C6.2 72.69, 2.31 80.53, -0.61 90.19" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(543.8161248538352 320.0588716753464) rotate(0 142.27794773651564 47.398886441224136)"><path d="M0.05 -0.66 C47.33 14.9, 236.38 78.25, 283.79 94.26 M-1.38 1.61 C46.27 17.25, 238.58 80.22, 286.09 95.51" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(543.8161248538352 320.0588716753464) rotate(0 142.27794773651564 47.398886441224136)"><path d="M261.11 96.38 C267.7 94.82, 275.6 95.75, 286.09 95.51 M261.11 96.38 C269.72 96.9, 279.34 96.54, 286.09 95.51" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(543.8161248538352 320.0588716753464) rotate(0 142.27794773651564 47.398886441224136)"><path d="M266.4 80.12 C271.48 83.57, 277.75 89.5, 286.09 95.51 M266.4 80.12 C273.29 86.31, 281.05 91.65, 286.09 95.51" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(442.44937395137794 272.04955230132305) rotate(0 -76.44158795840961 0.7940286704358073)"><path d="M0.24 -0.07 C-25.2 0.27, -126.27 1.91, -151.79 2.24 M-1.09 -1.16 C-26.67 -1.18, -126.73 -0.29, -152.17 0.46" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(442.44937395137794 272.04955230132305) rotate(0 -76.44158795840961 0.7940286704358073)"><path d="M-128.83 -8.5 C-137.57 -3.32, -144.99 -1.87, -152.17 0.46 M-128.83 -8.5 C-137.14 -5.23, -143.22 -2.54, -152.17 0.46" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(442.44937395137794 272.04955230132305) rotate(0 -76.44158795840961 0.7940286704358073)"><path d="M-128.53 8.6 C-137.41 7.45, -144.94 2.58, -152.17 0.46 M-128.53 8.6 C-136.98 6.3, -143.16 3.44, -152.17 0.46" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(208.64934536155684 109.00298768494096) rotate(0 -30.185875762287225 57.21237099590196)"><path d="M-0.33 0.63 C-10.65 20.05, -51.53 96.63, -61.45 115.43 M1.7 -0.08 C-8.31 19.12, -48.97 94.78, -59.3 113.83" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(208.64934536155684 109.00298768494096) rotate(0 -30.185875762287225 57.21237099590196)"><path d="M-55.68 89.1 C-56.09 95.74, -56.71 106.92, -59.3 113.83 M-55.68 89.1 C-56.03 94.08, -57.59 99.97, -59.3 113.83" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(208.64934536155684 109.00298768494096) rotate(0 -30.185875762287225 57.21237099590196)"><path d="M-40.62 97.21 C-46.11 101.05, -51.86 109.45, -59.3 113.83 M-40.62 97.21 C-44.29 100.43, -49.11 104.57, -59.3 113.83" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask></svg>
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@fr-data-fabric/chatbot-api-nest",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.js",
5
+ "scripts": {
6
+ "build": "tsc -p tsconfig.json"
7
+ },
8
+ "author": "PM Data Fabric",
9
+ "license": "Apache-2.0",
10
+ "description": "",
11
+ "dependencies": {
12
+ "@nestjs/common": "^11.1.16",
13
+ "@nestjs/event-emitter": "^3.0.1",
14
+ "@nestjs/graphql": "^13.2.4",
15
+ "class-validator": "^0.14.4",
16
+ "langchain": "^1.2.30",
17
+ "rxjs": "^7.8.2"
18
+ },
19
+ "devDependencies": {
20
+ "@types/express": "^5.0.6"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ }
25
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ CONVERSATION_REPOSITORY,
3
+ ConversationRepository,
4
+ } from '@domain/interfaces/ConversationRepository';
5
+ import { SEND_CHAT_UC, SendChatUC } from '@domain/use-cases/chats/SendChatUC';
6
+ import {
7
+ CREATE_CONVERSATION_UC,
8
+ ICreateConversationUC,
9
+ } from '@domain/use-cases/conversations/CreateConversationUC';
10
+ import { DeleteConversationUC } from '@domain/use-cases/conversations/DeleteConversationUC';
11
+ import {
12
+ GET_CONVERSATIONS_UC,
13
+ IGetConversationsUC,
14
+ } from '@domain/use-cases/conversations/GetConversationsUC';
15
+ import {
16
+ GET_CONVERSATION_UC,
17
+ IGetConversationUC,
18
+ } from '@domain/use-cases/conversations/GetConversationUC';
19
+ import { UpdateConversationUC } from '@domain/use-cases/conversations/UpdateConversationUC';
20
+ import { DynamicModule, Module, Type } from '@nestjs/common';
21
+ import { GqlTypeReference } from '@nestjs/graphql';
22
+ import { ChatsController } from 'src/inputs/controllers/ChatsController';
23
+ import { GetChatsResolver } from 'src/inputs/resolvers/ChatsResolver';
24
+ import { GetConversationsResolver } from 'src/inputs/resolvers/ConversationsResolver';
25
+
26
+ export type ChatbotApiModuleOptions = {
27
+ useCases: {
28
+ getConversation: Type<IGetConversationUC>;
29
+ getConversations: Type<IGetConversationsUC>;
30
+ createConversation: Type<ICreateConversationUC>;
31
+ sendChat: Type<SendChatUC<never>>;
32
+ };
33
+ conversationRepository: Type<ConversationRepository>;
34
+ gql: {
35
+ GqlConversation: GqlTypeReference;
36
+ GqlChat: GqlTypeReference;
37
+ GqlUser: GqlTypeReference;
38
+ GqlChatSource: GqlTypeReference;
39
+ GqlChatTextContent: GqlTypeReference;
40
+ GqlToolUse: GqlTypeReference;
41
+ };
42
+ };
43
+
44
+ @Module({})
45
+ export class ChatbotApiModule {
46
+ static register(options: ChatbotApiModuleOptions): DynamicModule {
47
+ return {
48
+ module: ChatbotApiModule,
49
+ providers: [
50
+ // Repositories
51
+ {
52
+ provide: CONVERSATION_REPOSITORY,
53
+ useClass: options.conversationRepository,
54
+ },
55
+ // Use cases
56
+ {
57
+ provide: GET_CONVERSATION_UC,
58
+ useClass: options.useCases.getConversation,
59
+ },
60
+ {
61
+ provide: GET_CONVERSATIONS_UC,
62
+ useClass: options.useCases.getConversations,
63
+ },
64
+ {
65
+ provide: CREATE_CONVERSATION_UC,
66
+ useClass: options.useCases.createConversation,
67
+ },
68
+ DeleteConversationUC,
69
+ UpdateConversationUC,
70
+ {
71
+ provide: SEND_CHAT_UC,
72
+ useClass: options.useCases.sendChat,
73
+ },
74
+ // Resolvers
75
+ GetConversationsResolver(
76
+ options.gql.GqlConversation,
77
+ options.gql.GqlChat,
78
+ options.gql.GqlUser,
79
+ ),
80
+ GetChatsResolver(
81
+ options.gql.GqlChat,
82
+ options.gql.GqlChatSource,
83
+ options.gql.GqlChatTextContent,
84
+ options.gql.GqlToolUse,
85
+ ),
86
+ ],
87
+ controllers: [ChatsController],
88
+ };
89
+ }
90
+ }
@@ -0,0 +1,13 @@
1
+ import { ChatSourceEntity } from '@domain/entities/ChatSourceEntity';
2
+ import { ChatTextContentEntity } from '@domain/entities/ChatTextContentEntity';
3
+ import { ToolUseEntity } from '@domain/entities/ToolUseEntity';
4
+
5
+ export interface ChatEntity {
6
+ id: string;
7
+ createdAt: Date;
8
+ updatedAt: Date;
9
+
10
+ _sources: Promise<ChatSourceEntity[]>;
11
+ _textContents: Promise<ChatTextContentEntity[]>;
12
+ _toolUses: Promise<ToolUseEntity[]>;
13
+ }
@@ -0,0 +1,6 @@
1
+ export interface ChatSourceEntity {
2
+ content: string;
3
+ link: string;
4
+ title: string;
5
+ index: number;
6
+ }
@@ -0,0 +1,4 @@
1
+ export interface ChatTextContentEntity {
2
+ content: string;
3
+ order: number;
4
+ }
@@ -0,0 +1,10 @@
1
+ import { ChatEntity } from '@domain/entities/ChatEntity';
2
+ import { UserEntity } from '@domain/entities/UserEntity';
3
+
4
+ export interface ConversationEntity {
5
+ id: string;
6
+ title: string;
7
+ shareId: string | null;
8
+ _chats: Promise<ChatEntity[]>;
9
+ _user: Promise<UserEntity>;
10
+ }
@@ -0,0 +1,3 @@
1
+ export interface DocumentEntity {
2
+ id: string;
3
+ }
@@ -0,0 +1,6 @@
1
+ export interface ToolUseEntity {
2
+ name: string;
3
+ input: string;
4
+ output: string | null;
5
+ order: number;
6
+ }
@@ -0,0 +1,3 @@
1
+ export interface UserEntity {
2
+ id: string;
3
+ }
@@ -0,0 +1,7 @@
1
+ import { ChatEntity } from '@domain/entities/ChatEntity';
2
+
3
+ export const CHAT_REPOSITORY = 'ChatRepository';
4
+
5
+ export interface ChatRepository {
6
+ save: (chat: ChatEntity) => Promise<ChatEntity>;
7
+ }
@@ -0,0 +1,8 @@
1
+ import { ConversationEntity } from '@domain/entities/ConversationEntity';
2
+
3
+ export const CONVERSATION_REPOSITORY = 'ConversationRepository';
4
+
5
+ export interface ConversationRepository {
6
+ save: (conversation: ConversationEntity) => Promise<ConversationEntity>;
7
+ remove: (conversation: ConversationEntity) => Promise<ConversationEntity>;
8
+ }
@@ -0,0 +1,15 @@
1
+ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+
3
+ export const LLM_SERVICE = 'LLMService';
4
+
5
+ type ProvidersOptions = {
6
+ temperature: number;
7
+ streaming: boolean;
8
+ model: string;
9
+ provider: string;
10
+ };
11
+ export type LLMOptions = ProvidersOptions;
12
+
13
+ export interface LLMService {
14
+ getLLM(options: LLMOptions): BaseChatModel;
15
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseMessage } from 'langchain';
2
+
3
+ export const PROMPT_SERVICE = 'PromptService';
4
+
5
+ export interface PromptService {
6
+ getPrompt(
7
+ prompt: { name: string; version: string },
8
+ values: Record<string, unknown>,
9
+ ): Promise<BaseMessage[]>;
10
+ }
@@ -0,0 +1,28 @@
1
+ import { UserEntity } from '@domain/entities/UserEntity';
2
+ import { Field, ID, InputType, Int } from '@nestjs/graphql';
3
+
4
+ export type UCInput<Input> = {
5
+ input: Input;
6
+ currentUser: UserEntity;
7
+ };
8
+
9
+ @InputType()
10
+ export class DeleteByIdInput {
11
+ @Field(() => ID)
12
+ id!: string;
13
+ }
14
+
15
+ export type PaginatedOutput<Item> = {
16
+ items: Item[];
17
+ totalCount: number;
18
+ hasNextPage: boolean;
19
+ };
20
+
21
+ @InputType()
22
+ export class PaginatedInput {
23
+ @Field(() => Int)
24
+ limit!: number;
25
+
26
+ @Field(() => Int)
27
+ offset!: number;
28
+ }
@@ -0,0 +1,126 @@
1
+ import { ConversationEntity } from '@domain/entities/ConversationEntity';
2
+ import { DocumentEntity } from '@domain/entities/DocumentEntity';
3
+ import { UserEntity } from '@domain/entities/UserEntity';
4
+ import {
5
+ AvailableTool,
6
+ StreamEvents,
7
+ ToolNames,
8
+ ToolOptions,
9
+ } from '@domain/use-cases/chats/chat.types';
10
+ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
11
+ import {
12
+ AIMessageChunk,
13
+ BaseMessage,
14
+ createAgent,
15
+ DynamicStructuredTool,
16
+ ToolMessage,
17
+ } from 'langchain';
18
+ import { Observable } from 'rxjs';
19
+
20
+ export type GetChatCompletionInput<AvailableTools extends AvailableTool[]> = {
21
+ message: string;
22
+ previousMessages: { role: 'user' | 'assistant'; content: string }[];
23
+ conversation: ConversationEntity;
24
+ runId: string;
25
+ tools?: AvailableTools;
26
+ documents: DocumentEntity[];
27
+ currentUser: UserEntity;
28
+ model?: string;
29
+ };
30
+
31
+ export abstract class GetChatCompletionUC<
32
+ AvailableTools extends AvailableTool[],
33
+ > {
34
+ abstract getTools(
35
+ toolOptions: ToolOptions,
36
+ selectedTools: AvailableTools,
37
+ ): DynamicStructuredTool[];
38
+
39
+ abstract getLLM(options: { model?: string }): BaseChatModel;
40
+ abstract getPrompt(
41
+ question: string,
42
+ documents: DocumentEntity[],
43
+ ): Promise<BaseMessage[]>;
44
+
45
+ execute(input: GetChatCompletionInput<AvailableTools>) {
46
+ return new Observable<StreamEvents<AvailableTools>>((observer) => {
47
+ const model = this.getLLM({
48
+ model: input.model,
49
+ });
50
+
51
+ let sourceIndex = 0;
52
+ const toolOptions: ToolOptions = {
53
+ getSourceIndex() {
54
+ return ++sourceIndex;
55
+ },
56
+ addSources(sources) {
57
+ observer.next({ event: 'sources_add', sources });
58
+ },
59
+ currentUser: input.currentUser,
60
+ };
61
+
62
+ const agent = createAgent({
63
+ model,
64
+ tools: input.tools ? this.getTools(toolOptions, input.tools) : [],
65
+ });
66
+
67
+ void (async () => {
68
+ const prompt = await this.getPrompt(input.message, input.documents);
69
+
70
+ const eventStream = agent.streamEvents(
71
+ { messages: prompt },
72
+ { streamMode: 'messages', configurable: { runId: input.runId } },
73
+ );
74
+
75
+ let lastToolId: string | undefined = undefined;
76
+ for await (const event of eventStream) {
77
+ if (event.event === 'on_tool_end') {
78
+ const output = event.data.output as ToolMessage;
79
+ observer.next({
80
+ event: 'tool_end',
81
+ name: event.name as ToolNames<AvailableTools>,
82
+ id: output.tool_call_id,
83
+ input: (event.data.input as { input: string }).input,
84
+ output: output.content,
85
+ });
86
+ }
87
+ if (event.event === 'on_tool_start' && lastToolId) {
88
+ observer.next({
89
+ event: 'tool_start',
90
+ name: event.name as ToolNames<AvailableTools>,
91
+ id: lastToolId,
92
+ input: (event.data.input as { input: string }).input,
93
+ });
94
+ }
95
+ if (event.event === 'on_chat_model_stream') {
96
+ const chunk = event.data.chunk as AIMessageChunk;
97
+
98
+ if (chunk.tool_call_chunks?.length) {
99
+ const toolCallChunk = chunk.tool_call_chunks[0];
100
+ if (toolCallChunk.name && toolCallChunk.id) {
101
+ lastToolId = toolCallChunk.id;
102
+ observer.next({
103
+ event: 'tool_stream_start',
104
+ name: toolCallChunk.name as ToolNames<AvailableTools>,
105
+ id: toolCallChunk.id,
106
+ });
107
+ } else if (lastToolId && toolCallChunk.args) {
108
+ observer.next({
109
+ event: 'tool_stream',
110
+ id: lastToolId,
111
+ input: toolCallChunk.args,
112
+ });
113
+ }
114
+ } else if (chunk.content) {
115
+ observer.next({
116
+ event: 'chat_stream',
117
+ content: chunk.content as string,
118
+ });
119
+ }
120
+ }
121
+ }
122
+ observer.complete();
123
+ })();
124
+ });
125
+ }
126
+ }
@@ -0,0 +1,202 @@
1
+ import { ChatEntity } from '@domain/entities/ChatEntity';
2
+ import { ChatSourceEntity } from '@domain/entities/ChatSourceEntity';
3
+ import { ChatTextContentEntity } from '@domain/entities/ChatTextContentEntity';
4
+ import { ConversationEntity } from '@domain/entities/ConversationEntity';
5
+ import { DocumentEntity } from '@domain/entities/DocumentEntity';
6
+ import { ToolUseEntity } from '@domain/entities/ToolUseEntity';
7
+ import { UserEntity } from '@domain/entities/UserEntity';
8
+ import type { ChatRepository } from '@domain/interfaces/ChatRepository';
9
+ import { UCInput } from '@domain/use-cases/_common';
10
+ import {
11
+ AvailableTool,
12
+ ChatStreamEvents,
13
+ } from '@domain/use-cases/chats/chat.types';
14
+ import { GetChatCompletionUC } from '@domain/use-cases/chats/GetChatCompletionUC';
15
+ import type { IGetConversationUC } from '@domain/use-cases/conversations/GetConversationUC';
16
+ import { EventEmitter2 } from '@nestjs/event-emitter';
17
+ import {
18
+ IsArray,
19
+ IsNotEmpty,
20
+ IsOptional,
21
+ IsString,
22
+ ValidateNested,
23
+ } from 'class-validator';
24
+ import { Observable } from 'rxjs';
25
+
26
+ export class SendMessageInput<AvailableTools extends AvailableTool[]> {
27
+ @IsString()
28
+ @IsNotEmpty()
29
+ conversationId!: string;
30
+
31
+ @IsString()
32
+ @IsNotEmpty()
33
+ content!: string;
34
+
35
+ @IsArray()
36
+ @ValidateNested({ each: true })
37
+ @IsOptional()
38
+ selectedTools?: AvailableTools;
39
+
40
+ @IsArray()
41
+ @IsString({ each: true })
42
+ @IsOptional()
43
+ documentIds?: string[];
44
+
45
+ @IsString()
46
+ @IsNotEmpty()
47
+ @IsOptional()
48
+ model?: string;
49
+ }
50
+
51
+ export const SEND_CHAT_UC = 'SendChatUC';
52
+
53
+ export abstract class SendChatUC<AvailableTools extends AvailableTool[]> {
54
+ constructor(
55
+ private readonly getConversationUC: IGetConversationUC,
56
+ private readonly chatRepository: ChatRepository,
57
+ private readonly eventEmitter: EventEmitter2,
58
+ private readonly getChatCompletionUC: GetChatCompletionUC<AvailableTools>,
59
+ ) {}
60
+
61
+ abstract getDocuments(
62
+ documentIds: string[],
63
+ currentUser: UserEntity,
64
+ ): Promise<DocumentEntity[]>;
65
+
66
+ abstract createChatEntity(
67
+ role: 'user' | 'assistant',
68
+ content: string,
69
+ conversation: ConversationEntity,
70
+ documents?: DocumentEntity[],
71
+ ): ChatEntity;
72
+
73
+ async execute({
74
+ input,
75
+ currentUser,
76
+ }: UCInput<SendMessageInput<AvailableTools>>) {
77
+ const { conversationId, content, selectedTools, documentIds, model } =
78
+ input;
79
+ const conversation = await this.getConversationUC.execute({
80
+ input: { id: conversationId },
81
+ currentUser,
82
+ });
83
+
84
+ let documents: DocumentEntity[] = [];
85
+ if (documentIds && documentIds.length) {
86
+ documents = await this.getDocuments(documentIds, currentUser);
87
+
88
+ if (documents.length !== documentIds.length) {
89
+ throw new Error('Some documents not found');
90
+ }
91
+ }
92
+
93
+ const userMessage = this.createChatEntity(
94
+ 'user',
95
+ input.content,
96
+ conversation,
97
+ documents,
98
+ );
99
+ const assistantMessage = this.createChatEntity(
100
+ 'assistant',
101
+ '',
102
+ conversation,
103
+ );
104
+ await this.chatRepository.save(userMessage);
105
+ await this.chatRepository.save(assistantMessage);
106
+
107
+ this.eventEmitter.emit('message.new', userMessage);
108
+
109
+ const stream = this.getChatCompletionUC.execute({
110
+ message: content,
111
+ previousMessages: [],
112
+ conversation,
113
+ runId: assistantMessage.id,
114
+ tools: selectedTools,
115
+ documents,
116
+ currentUser,
117
+ model,
118
+ });
119
+
120
+ const tools = new Map<string, ToolUseEntity>();
121
+ const sources: ChatSourceEntity[] = [];
122
+ const chatCompletion: ChatTextContentEntity[] = [];
123
+ let textContent: string = '';
124
+ let order = 0;
125
+ return new Observable<ChatStreamEvents<AvailableTools>>((observer) => {
126
+ observer.next({ event: 'user_message_id', id: userMessage.id });
127
+ observer.next({ event: 'assistant_message_id', id: assistantMessage.id });
128
+ stream.subscribe({
129
+ next: (event) => {
130
+ observer.next(event);
131
+ if (event.event === 'tool_start') {
132
+ if (textContent) {
133
+ chatCompletion.push({
134
+ content: textContent,
135
+ order: order++,
136
+ });
137
+ textContent = '';
138
+ }
139
+ const tool: ToolUseEntity = {
140
+ name: event.name,
141
+ input: JSON.stringify(event.input),
142
+ output: null,
143
+ order: order++,
144
+ };
145
+ tools.set(event.id, tool);
146
+ } else if (event.event === 'tool_stream_start') {
147
+ // Do nothing at the moment
148
+ } else if (event.event === 'tool_end') {
149
+ if (!tools.has(event.id)) {
150
+ // This should never happen
151
+ } else {
152
+ const tool = tools.get(event.id);
153
+ if (tool) {
154
+ tool.input = event.input;
155
+ tool.output = JSON.stringify(event.output);
156
+ }
157
+ }
158
+ } else if (event.event == 'sources_add') {
159
+ sources.push(
160
+ ...event.sources.map(
161
+ (s): ChatSourceEntity => ({
162
+ content: s.content,
163
+ link: s.link,
164
+ title: s.title,
165
+ index: s.index,
166
+ }),
167
+ ),
168
+ );
169
+ } else if (event.event === 'chat_stream') {
170
+ textContent += event.content;
171
+ }
172
+ },
173
+ complete: () => {
174
+ void (async () => {
175
+ if (textContent) {
176
+ chatCompletion.push({
177
+ content: textContent,
178
+ order: order++,
179
+ });
180
+ textContent = '';
181
+ }
182
+ await this.saveToolUse(Array.from(tools.values()));
183
+ await this.saveChatSources(sources);
184
+ await this.saveChatTextContent(chatCompletion);
185
+
186
+ this.eventEmitter.emit('message.new', assistantMessage);
187
+
188
+ observer.complete();
189
+ })();
190
+ },
191
+ });
192
+ });
193
+ }
194
+
195
+ abstract saveChatSources(sources: ChatSourceEntity[]): Promise<void>;
196
+
197
+ abstract saveChatTextContent(
198
+ chatCompletion: ChatTextContentEntity[],
199
+ ): Promise<void>;
200
+
201
+ abstract saveToolUse(tools: ToolUseEntity[]): Promise<void>;
202
+ }