@futdevpro/nts-dynamo 1.15.15 → 1.15.17

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 (348) hide show
  1. package/.c8rc.json +26 -26
  2. package/.copilot/patterns.json +7 -7
  3. package/.cursor/rules/__assistant_guide.mdc +30 -30
  4. package/.cursor/rules/_ag_backend-structure.mdc +85 -85
  5. package/.cursor/rules/_ag_backend.mdc +16 -16
  6. package/.cursor/rules/_ag_frontend-structure.mdc +86 -86
  7. package/.cursor/rules/_ag_frontend.mdc +39 -39
  8. package/.cursor/rules/_ag_import-rules.mdc +44 -44
  9. package/.cursor/rules/_ag_naming.mdc +115 -115
  10. package/.cursor/rules/_ag_should-be.mdc +6 -6
  11. package/.cursor/rules/ai_development_guide.md +60 -60
  12. package/.cursor/rules/cursor-rules.md +160 -160
  13. package/.cursor/rules/default-command.mdc +464 -464
  14. package/.cursor/rules/error_code_pattern.md +39 -39
  15. package/.cursor/rules/saved rule mcp server use.md +15 -15
  16. package/.dynamo/version-bump.config.json +5 -0
  17. package/.github/workflows/main.yml +426 -393
  18. package/.husky/pre-commit +1 -0
  19. package/.vscode/settings.json +10 -10
  20. package/HOWTO.md +15 -15
  21. package/LICENSE +21 -21
  22. package/__documentations/2026-04-28-logs-module.md +49 -0
  23. package/__documentations/nts-integration-tests-2026-03-17.md +26 -26
  24. package/_specifications/BACKLOG.md +50 -50
  25. package/_specifications/TODO.md +15 -15
  26. package/_specifications/agent.md +138 -138
  27. package/eslint.config.js +3 -3
  28. package/nodemon.json +24 -24
  29. package/package.json +343 -362
  30. package/pipeline.cicd.config.json +152 -0
  31. package/pnpm-workspace.yaml +2 -0
  32. package/scripts/run-coverage-tests.js +28 -28
  33. package/spec/support/helpers/spec-reporter-loader.js +359 -359
  34. package/spec/support/helpers/ts-node-helper.js +93 -93
  35. package/spec/support/jasmine.coverage.json +24 -24
  36. package/spec/support/jasmine.json +24 -24
  37. package/src/_collections/archive.util.spec.ts +57 -57
  38. package/src/_collections/archive.util.ts +18 -18
  39. package/src/_collections/atlas-default-db-options.const.ts +9 -9
  40. package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -11
  41. package/src/_collections/default-fallback-cache-max-age.const.ts +2 -2
  42. package/src/_collections/default-not-found-page.const.spec.ts +19 -19
  43. package/src/_collections/default-not-found-page.const.ts +22 -22
  44. package/src/_collections/default-socket-path.const.spec.ts +12 -12
  45. package/src/_collections/default-socket-path.const.ts +2 -2
  46. package/src/_collections/get-environment-settings.util.spec.ts +210 -210
  47. package/src/_collections/get-environment-settings.util.ts +48 -48
  48. package/src/_collections/sample.env +21 -21
  49. package/src/_collections/star.controller.spec.ts +224 -224
  50. package/src/_collections/star.controller.ts +129 -129
  51. package/src/_enums/data-model-type.enum.ts +14 -14
  52. package/src/_enums/data-service-function.enum.ts +24 -24
  53. package/src/_enums/predefined-data-types.enum.ts +16 -16
  54. package/src/_enums/route-security.enum.ts +12 -12
  55. package/src/_models/control-models/api-call-params.control-model.spec.ts +152 -152
  56. package/src/_models/control-models/api-call-params.control-model.ts +142 -142
  57. package/src/_models/control-models/app-ext-system-controls.control-model.spec.ts +52 -52
  58. package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
  59. package/src/_models/control-models/app-params.control-model.spec.ts +225 -225
  60. package/src/_models/control-models/app-params.control-model.ts +136 -136
  61. package/src/_models/control-models/app-system-controls.control-model.spec.ts +31 -31
  62. package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
  63. package/src/_models/control-models/endpoint-params.control-model.spec.ts +578 -578
  64. package/src/_models/control-models/endpoint-params.control-model.ts +526 -526
  65. package/src/_models/control-models/http-settings.control-model.spec.ts +77 -77
  66. package/src/_models/control-models/http-settings.control-model.ts +37 -37
  67. package/src/_models/control-models/system-control.control-model.spec.ts +27 -27
  68. package/src/_models/control-models/system-control.control-model.ts +12 -12
  69. package/src/_models/interfaces/certification-settings.interface.ts +7 -7
  70. package/src/_models/interfaces/environment-settings.interface.ts +59 -59
  71. package/src/_models/interfaces/global-log-settings.interface.ts +108 -108
  72. package/src/_models/interfaces/global-service-settings.interface.ts +47 -47
  73. package/src/_models/interfaces/routing-module-settings.interface.ts +21 -21
  74. package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -29
  75. package/src/_models/interfaces/static-client-settings.interface.ts +28 -28
  76. package/src/_models/types/db-update.type.ts +100 -100
  77. package/src/_modules/ai/_models/ai-input-interfaces.ts +117 -117
  78. package/src/_modules/ai/_models/ai-test-generation-result.interface.ts +16 -16
  79. package/src/_modules/ai/_modules/anthropic/_services/aai-user-key.control-service.ts +138 -138
  80. package/src/_modules/ai/_modules/anthropic/index.ts +5 -5
  81. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.spec.ts +242 -242
  82. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.ts +639 -639
  83. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.spec.ts +209 -209
  84. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.ts +85 -85
  85. package/src/_modules/ai/_modules/document-ai/_enums/dai-compare-result-type.enum.ts +7 -7
  86. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-chunk.data-model.ts +146 -146
  87. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-page.data-model.ts +162 -162
  88. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-document.data-model.ts +99 -99
  89. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-chunk-compare-result.interface.ts +18 -18
  90. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-page-compare-result.interface.ts +19 -19
  91. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-document-compare-result.interface.ts +25 -25
  92. package/src/_modules/ai/_modules/document-ai/index.ts +28 -28
  93. package/src/_modules/ai/_modules/fdp-ai/_services/fdpai-user-key.control-service.ts +189 -189
  94. package/src/_modules/ai/_modules/fdp-ai/index.ts +5 -5
  95. package/src/_modules/ai/_modules/open-ai/_collections/oai-global-settings.const.ts +9 -9
  96. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests-hu.conts.ts +82 -82
  97. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests.conts.ts +75 -75
  98. package/src/_modules/ai/_modules/open-ai/_enums/oai-gpt-message-role.enum.ts +45 -45
  99. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-global-settings.interface.ts +7 -7
  100. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-gpt-message.interface.ts +7 -7
  101. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-llm-predefined-requests.interface.ts +57 -57
  102. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-doc-chunk-data.service.ts +292 -292
  103. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-document.data-service.spec.ts +342 -342
  104. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.spec.ts +550 -550
  105. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.ts +630 -630
  106. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +240 -240
  107. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.ts +98 -98
  108. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.spec.ts +462 -462
  109. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +615 -615
  110. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +437 -437
  111. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +833 -833
  112. package/src/_modules/ai/_modules/open-ai/_services/oai-user-key.control-service.ts +157 -157
  113. package/src/_modules/ai/_services/ai-embedding.service-base.spec.ts +98 -98
  114. package/src/_modules/ai/_services/ai-embedding.service-base.ts +48 -48
  115. package/src/_modules/ai/_services/ai-llm-chat.service-base.spec.ts +229 -229
  116. package/src/_modules/ai/_services/ai-llm-chat.service-base.ts +68 -68
  117. package/src/_modules/ai/_services/ai-llm.service-base.spec.ts +250 -250
  118. package/src/_modules/ai/_services/ai-llm.service-base.ts +332 -332
  119. package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +79 -79
  120. package/src/_modules/ai/_services/ai-provider.service-base.ts +29 -29
  121. package/src/_modules/ai/_services/ai-user-key.service-base.ts +59 -59
  122. package/src/_modules/ai/index.ts +13 -13
  123. package/src/_modules/assistant/_collections/ass-global-settings.const.ts +13 -13
  124. package/src/_modules/assistant/_collections/ass.util.spec.ts +176 -176
  125. package/src/_modules/assistant/_collections/ass.util.ts +50 -50
  126. package/src/_modules/assistant/_models/ass-global-settings.interface.ts +15 -15
  127. package/src/_modules/assistant/_services/ass-io.control-service.spec.ts +140 -140
  128. package/src/_modules/assistant/_services/ass-main.control-service.spec.ts +192 -192
  129. package/src/_modules/assistant/_services/ass-main.control-service.ts +107 -107
  130. package/src/_modules/bot/_collections/bot-default-commands.const.ts +12 -12
  131. package/src/_modules/bot/_collections/bot-global-settings.const.ts +39 -39
  132. package/src/_modules/bot/_models/bot-channel-wrapper.interface.ts +62 -62
  133. package/src/_modules/bot/_models/bot-command.interface.ts +8 -8
  134. package/src/_modules/bot/_models/bot-global-settings.interface.ts +96 -96
  135. package/src/_modules/bot/_models/bot-last-mention-date.interface.ts +6 -6
  136. package/src/_modules/bot/_models/bot-last-message-date.interface.ts +5 -5
  137. package/src/_modules/bot/_models/bot-user-wrapper.interface.ts +41 -41
  138. package/src/_modules/bot/_modules/discord-bot/_models/dib-platform.types.ts +9 -9
  139. package/src/_modules/bot/_modules/discord-bot/_services/dib-messaging-provider.control-service.spec.ts +431 -431
  140. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.spec.ts +160 -160
  141. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.ts +55 -55
  142. package/src/_modules/bot/_modules/dynamo-bot/_models/dyb-platform.types.ts +15 -15
  143. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.spec.ts +374 -374
  144. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.ts +447 -447
  145. package/src/_modules/bot/_modules/dynamo-bot/index.ts +15 -15
  146. package/src/_modules/bot/_modules/slack-bot/_models/slb-platform.types.ts +9 -9
  147. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.spec.ts +344 -344
  148. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.ts +197 -197
  149. package/src/_modules/bot/_modules/teams-bot/_models/teb-platform.types.ts +9 -9
  150. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.spec.ts +345 -345
  151. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.ts +197 -197
  152. package/src/_modules/bot/_services/bot-commands.control-service.spec.ts +116 -116
  153. package/src/_modules/bot/_services/bot-io.control-service.spec.ts +285 -285
  154. package/src/_modules/bot/_services/bot-main.control-service.spec.ts +208 -208
  155. package/src/_modules/bot/_services/bot-messaging-provider.service-base.spec.ts +349 -349
  156. package/src/_modules/bot/_services/bot-routines.control-service.spec.ts +111 -111
  157. package/src/_modules/custom-data/custom-data.controller.spec.ts +49 -49
  158. package/src/_modules/custom-data/custom-data.controller.ts +67 -67
  159. package/src/_modules/custom-data/custom-data.data-service.spec.ts +54 -54
  160. package/src/_modules/custom-data/custom-data.data-service.ts +21 -21
  161. package/src/_modules/custom-data/get-custom-data-routing-module.util.spec.ts +28 -28
  162. package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +24 -24
  163. package/src/_modules/custom-data/index.ts +9 -9
  164. package/src/_modules/defaults/_collections/default-endpoints.util.ts +487 -487
  165. package/src/_modules/defaults/_models/default-user.data-model.ts +72 -72
  166. package/src/_modules/defaults/_services/default-auth.service.spec.ts +269 -269
  167. package/src/_modules/defaults/_services/default-auth.service.ts +177 -177
  168. package/src/_modules/defaults/_services/default-socket-events.service.spec.ts +42 -42
  169. package/src/_modules/defaults/_services/default-socket-events.service.ts +61 -61
  170. package/src/_modules/defaults/_services/default-user.data-service.spec.ts +187 -187
  171. package/src/_modules/defaults/_services/default-user.data-service.ts +98 -98
  172. package/src/_modules/defaults/index.ts +17 -17
  173. package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +19 -19
  174. package/src/_modules/discord-assistant/_collections/dias.util.spec.ts +366 -366
  175. package/src/_modules/discord-assistant/_collections/dias.util.ts +132 -132
  176. package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +19 -19
  177. package/src/_modules/discord-assistant/_models/dias-knowledge.data-model.ts +52 -52
  178. package/src/_modules/discord-assistant/_services/dias-chunk.data-service.ts +177 -177
  179. package/src/_modules/discord-assistant/_services/dias-io.control-service.spec.ts +108 -108
  180. package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +69 -69
  181. package/src/_modules/discord-assistant/_services/dias-main.control-service.spec.ts +22 -22
  182. package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +27 -27
  183. package/src/_modules/discord-assistant/_services/dias.service-base.spec.ts +195 -195
  184. package/src/_modules/discord-assistant/_services/dias.service-base.ts +76 -76
  185. package/src/_modules/discord-assistant/index.ts +38 -38
  186. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.spec.ts +34 -34
  187. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.ts +11 -11
  188. package/src/_modules/discord-assistant-voiced/index.ts +36 -36
  189. package/src/_modules/discord-bot/_collections/dibo-default-commands.const.ts +16 -16
  190. package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +55 -55
  191. package/src/_modules/discord-bot/_collections/dibo-operations.util.spec.ts +214 -214
  192. package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +387 -387
  193. package/src/_modules/discord-bot/_models/dibo-command.interface.ts +12 -12
  194. package/src/_modules/discord-bot/_models/dibo-global-settings.interface.ts +98 -98
  195. package/src/_modules/discord-bot/_models/dibo-last-mention-date.inteface.ts +7 -7
  196. package/src/_modules/discord-bot/_models/dibo-last-message-date.interface.ts +6 -6
  197. package/src/_modules/discord-bot/_services/dibo-commands.control-service.spec.ts +154 -154
  198. package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +153 -153
  199. package/src/_modules/discord-bot/_services/dibo-io.control-service.spec.ts +264 -264
  200. package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +306 -306
  201. package/src/_modules/discord-bot/_services/dibo-main.control-service.spec.ts +408 -408
  202. package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +487 -487
  203. package/src/_modules/discord-bot/_services/dibo-routines.control-service.spec.ts +105 -105
  204. package/src/_modules/discord-bot/index.ts +36 -36
  205. package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +19 -19
  206. package/src/_modules/local-vector-search/_models/lvs-search-result.interface.ts +17 -17
  207. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.spec.ts +418 -418
  208. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.ts +276 -276
  209. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +345 -345
  210. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +330 -330
  211. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +393 -393
  212. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +220 -220
  213. package/src/_modules/local-vector-search/index.ts +11 -11
  214. package/src/_modules/messaging/README.md +354 -354
  215. package/src/_modules/messaging/_collections/get-messaging-routing-module.util.ts +26 -26
  216. package/src/_modules/messaging/_collections/msg-global-settings.const.ts +22 -22
  217. package/src/_modules/messaging/_collections/msg.util.spec.ts +226 -226
  218. package/src/_modules/messaging/_models/msg-global-settings.interface.ts +37 -37
  219. package/src/_modules/messaging/_services/msg-conversation.data-service.ts +146 -146
  220. package/src/_modules/messaging/_services/msg-events.service.spec.ts +219 -219
  221. package/src/_modules/messaging/_services/msg-events.service.ts +267 -267
  222. package/src/_modules/messaging/_services/msg-integration.control-service.ts +179 -179
  223. package/src/_modules/messaging/_services/msg-main.control-service.spec.ts +147 -147
  224. package/src/_modules/messaging/_services/msg-main.control-service.ts +571 -571
  225. package/src/_modules/messaging/_services/msg-message.data-service.ts +129 -129
  226. package/src/_modules/messaging/_services/msg.controller.spec.ts +201 -201
  227. package/src/_modules/messaging/index.ts +30 -30
  228. package/src/_modules/mock/app-extended-server.mock.ts +201 -201
  229. package/src/_modules/mock/app-integration-test.mock.ts +51 -51
  230. package/src/_modules/mock/app-params.mock.spec.ts +21 -21
  231. package/src/_modules/mock/app-params.mock.ts +9 -9
  232. package/src/_modules/mock/app-server.mock.ts +188 -188
  233. package/src/_modules/mock/auth-service.mock.spec.ts +47 -47
  234. package/src/_modules/mock/auth-service.mock.ts +28 -28
  235. package/src/_modules/mock/controller.mock.spec.ts +26 -26
  236. package/src/_modules/mock/controller.mock.ts +16 -16
  237. package/src/_modules/mock/data-model.mock.spec.ts +111 -111
  238. package/src/_modules/mock/data-model.mock.ts +82 -82
  239. package/src/_modules/mock/email-service-collection.mock.spec.ts +24 -24
  240. package/src/_modules/mock/email-service-collection.mock.ts +15 -15
  241. package/src/_modules/mock/email-service.mock.spec.ts +17 -17
  242. package/src/_modules/mock/email-service.mock.ts +20 -20
  243. package/src/_modules/mock/email-template.mock.html +14 -14
  244. package/src/_modules/mock/endpoint.mock.ts +91 -91
  245. package/src/_modules/mock/socket-client.mock.spec.ts +40 -40
  246. package/src/_modules/mock/socket-client.mock.ts +45 -45
  247. package/src/_modules/mock/socket-server.mock.spec.ts +44 -44
  248. package/src/_modules/mock/socket-server.mock.ts +46 -46
  249. package/src/_modules/oauth2/_routes/oauth2.controller.spec.ts +107 -107
  250. package/src/_modules/oauth2/_routes/oauth2.controller.ts +98 -98
  251. package/src/_modules/oauth2/_services/oauth2.auth-service.spec.ts +254 -254
  252. package/src/_modules/oauth2/_services/oauth2.auth-service.ts +232 -232
  253. package/src/_modules/oauth2/_services/oauth2.control-service.spec.ts +585 -585
  254. package/src/_modules/oauth2/_services/oauth2.control-service.ts +653 -653
  255. package/src/_modules/oauth2/index.ts +17 -17
  256. package/src/_modules/server/errors/errors.control-service.spec.ts +230 -230
  257. package/src/_modules/server/errors/errors.control-service.ts +69 -69
  258. package/src/_modules/server/errors/errors.controller.spec.ts +165 -165
  259. package/src/_modules/server/errors/errors.controller.ts +270 -270
  260. package/src/_modules/server/errors/errors.data-service.spec.ts +355 -355
  261. package/src/_modules/server/index.ts +30 -30
  262. package/src/_modules/server/server-status/server-status-snapshot.control-service.spec.ts +70 -70
  263. package/src/_modules/server/server-status/server-status-snapshot.control-service.ts +17 -17
  264. package/src/_modules/server/server-status/server-status-snapshot.data-service.spec.ts +77 -77
  265. package/src/_modules/server/server-status/server-status-snapshot.data-service.ts +37 -37
  266. package/src/_modules/server/server-status/server-status.control-service.spec.ts +516 -516
  267. package/src/_modules/server/server-status/server-status.control-service.ts +336 -336
  268. package/src/_modules/server/server-status/server-status.controller.spec.ts +156 -156
  269. package/src/_modules/server/server-status/server-status.controller.ts +131 -131
  270. package/src/_modules/socket/_enums/socket-security.enum.ts +11 -11
  271. package/src/_modules/socket/_models/socket-client-service-params.control-model.spec.ts +32 -32
  272. package/src/_modules/socket/_models/socket-client-service-params.control-model.ts +22 -22
  273. package/src/_modules/socket/_models/socket-presence.control-model.spec.ts +164 -164
  274. package/src/_modules/socket/_models/socket-presence.control-model.ts +210 -210
  275. package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +46 -46
  276. package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +22 -22
  277. package/src/_modules/socket/_services/socket-client.service.spec.ts +15 -15
  278. package/src/_modules/socket/_services/socket-client.service.ts +260 -260
  279. package/src/_modules/socket/_services/socket-server.service.spec.ts +11 -11
  280. package/src/_modules/socket/app-extended.integration.spec.ts +85 -85
  281. package/src/_modules/socket/app-extended.server.ts +630 -630
  282. package/src/_modules/socket/index.ts +42 -42
  283. package/src/_modules/test/get-test-routing-module.util.spec.ts +28 -28
  284. package/src/_modules/test/get-test-routing-module.util.ts +23 -23
  285. package/src/_modules/test/index.ts +11 -11
  286. package/src/_modules/test/test.controller.spec.ts +72 -72
  287. package/src/_modules/test/test.controller.ts +115 -115
  288. package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
  289. package/src/_modules/usage/index.ts +15 -15
  290. package/src/_modules/usage/usage.controller.spec.ts +81 -81
  291. package/src/_modules/usage/usage.controller.ts +126 -126
  292. package/src/_modules/usage/usage.data-service.spec.ts +332 -332
  293. package/src/_modules/usage/usage.data-service.ts +185 -185
  294. package/src/_services/base/api.service-base.spec.ts +125 -125
  295. package/src/_services/base/api.service-base.ts +74 -74
  296. package/src/_services/base/archive-data.service.spec.ts +196 -196
  297. package/src/_services/base/archive-data.service.ts +216 -216
  298. package/src/_services/base/data.service.spec.ts +493 -493
  299. package/src/_services/base/data.service.ts +2525 -2525
  300. package/src/_services/base/db.service.spec.ts +73 -73
  301. package/src/_services/base/db.service.ts +1575 -1575
  302. package/src/_services/base/singleton.service-base.spec.ts +28 -28
  303. package/src/_services/base/singleton.service-base.ts +24 -24
  304. package/src/_services/base/singleton.service.spec.ts +114 -114
  305. package/src/_services/base/singleton.service.ts +38 -38
  306. package/src/_services/core/api.service.spec.ts +140 -140
  307. package/src/_services/core/auth.service.spec.ts +159 -159
  308. package/src/_services/core/auth.service.ts +174 -174
  309. package/src/_services/core/email.service.spec.ts +85 -85
  310. package/src/_services/core/email.service.ts +742 -742
  311. package/src/_services/core/global.service.spec.ts +275 -275
  312. package/src/_services/core/global.service.ts +461 -461
  313. package/src/_services/core/service-collection.service.spec.ts +46 -46
  314. package/src/_services/core/service-collection.service.ts +6 -6
  315. package/src/_services/route/controller.service.spec.ts +53 -53
  316. package/src/_services/route/controller.service.ts +148 -148
  317. package/src/_services/route/routing-module.service.spec.ts +98 -98
  318. package/src/_services/route/routing-module.service.ts +330 -330
  319. package/src/_services/shared.static-service.spec.ts +99 -99
  320. package/src/_services/shared.static-service.ts +78 -78
  321. package/src/index.ts +94 -94
  322. package/tsconfig.app.json +12 -12
  323. package/tsconfig.json +42 -42
  324. package/build/_modules/logs/get-logs-routing-module.util.d.ts +0 -19
  325. package/build/_modules/logs/get-logs-routing-module.util.d.ts.map +0 -1
  326. package/build/_modules/logs/get-logs-routing-module.util.js +0 -32
  327. package/build/_modules/logs/get-logs-routing-module.util.js.map +0 -1
  328. package/build/_modules/logs/index.d.ts +0 -4
  329. package/build/_modules/logs/index.d.ts.map +0 -1
  330. package/build/_modules/logs/index.js +0 -10
  331. package/build/_modules/logs/index.js.map +0 -1
  332. package/build/_modules/logs/log-buffer.service.d.ts +0 -38
  333. package/build/_modules/logs/log-buffer.service.d.ts.map +0 -1
  334. package/build/_modules/logs/log-buffer.service.js +0 -97
  335. package/build/_modules/logs/log-buffer.service.js.map +0 -1
  336. package/build/_modules/logs/logs.controller.d.ts +0 -27
  337. package/build/_modules/logs/logs.controller.d.ts.map +0 -1
  338. package/build/_modules/logs/logs.controller.js +0 -90
  339. package/build/_modules/logs/logs.controller.js.map +0 -1
  340. package/build/_modules/logs/logs.service.d.ts +0 -40
  341. package/build/_modules/logs/logs.service.d.ts.map +0 -1
  342. package/build/_modules/logs/logs.service.js +0 -97
  343. package/build/_modules/logs/logs.service.js.map +0 -1
  344. package/src/_modules/logs/get-logs-routing-module.util.ts +0 -36
  345. package/src/_modules/logs/index.ts +0 -3
  346. package/src/_modules/logs/log-buffer.service.ts +0 -101
  347. package/src/_modules/logs/logs.controller.ts +0 -109
  348. package/src/_modules/logs/logs.service.ts +0 -100
@@ -1,833 +1,833 @@
1
- import { OpenAI } from 'openai';
2
-
3
- import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
4
- import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_Log, DyFM_notNull, DyFM_Object } from '@futdevpro/fsm-dynamo';
5
- import {
6
- DyFM_AI_Message,
7
- DyFM_AI_MessageRole,
8
- DyFM_AI_Provider,
9
- DyFM_AI_ProviderCapabilities,
10
- DyFM_AI_CallSettings,
11
- DyFM_AI_Config,
12
- DyFM_AI_LLM_Response
13
- } from '@futdevpro/fsm-dynamo/ai';
14
-
15
- import { DyNTS_global_settings } from '../../../../../_collections/global-settings.const';
16
- import { ChatCompletion } from 'openai/resources';
17
- import { ChatCompletionCreateParamsBase, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
18
- import { DyNTS_OAI_LLM_Predefined_Requests } from '../_models/interfaces/oai-llm-predefined-requests.interface';
19
- import { DyNTS_OAI_global_settings } from '../_collections/oai-global-settings.const';
20
- import { DyNTS_OAI_LLMDefaultPredefined_Requests } from '../_collections/oai-llm-predefined-requests.conts';
21
- import { DyNTS_AI_LLM_ServiceBase } from '../../../_services/ai-llm.service-base';
22
- import {
23
- DyFM_AI_Message_Input,
24
- DyFM_AI_GenericSelect_Input,
25
- DyFM_AI_GenericMultiSelect_Input,
26
- DyFM_AI_JSONKeysDescription_Input,
27
- DyFM_AI_JSONExactKeys_Input,
28
- DyFM_AI_MultiSelect_Input,
29
- DyFM_AI_ConversationBase_Input
30
- } from '../../../_models/ai-input-interfaces';
31
-
32
-
33
- /**
34
- * {
35
- * organization: 'org-XY',
36
- * apiKey: 'sk-XY',
37
- * project: 'proj_XY',
38
- * }
39
- */
40
-
41
- // Di Dictionary DiModel DiEz DiAz
42
-
43
- export class DyNTS_OAI_LLM_ServiceBase extends DyNTS_AI_LLM_ServiceBase {
44
-
45
- /* readonly defaultErrorUserMsg: string =
46
- `We encountered an unhandled Control Service Error, ` +
47
- `\nplease contact the responsible development team.`; */
48
-
49
- openai: OpenAI;
50
-
51
- readonly defaultSettings: DyFM_OAI_CallSettings;
52
-
53
- // Provider properties from DyNTS_AI_Provider_ServiceBase
54
- readonly aiProvider: DyFM_AI_Provider = DyFM_AI_Provider.OpenAI;
55
-
56
- readonly capabilities: DyFM_AI_ProviderCapabilities = {
57
- chat: true,
58
- embeddings: true,
59
- imageGeneration: true,
60
- vision: true,
61
- audioGeneration: true,
62
- audioAnalysis: true,
63
- functionCalling: true,
64
- streaming: true,
65
- batchOperations: true,
66
- maxContextLength: 128000,
67
- supportedModelTypes: ['gpt-4o', 'gpt-4o-mini', 'text-embedding-3-large', 'text-embedding-3-small']
68
- };
69
-
70
- /* get _debugLog(): boolean {
71
- return this.defaultSettings.debugLog;
72
- } */
73
-
74
- /* get defaultSystemPrompt(): string {
75
- return this.defaultSettings.systemPrompt;
76
- } */
77
-
78
- override get defaultModel(): DyFM_OAI_Model | string {
79
- return this.defaultSettings.useModel;
80
- }
81
-
82
- predefinedRequests: DyNTS_OAI_LLM_Predefined_Requests = DyNTS_OAI_LLMDefaultPredefined_Requests;
83
-
84
- constructor(
85
- set?: DyFM_OAI_Settings
86
- ) {
87
- super();
88
-
89
- DyNTS_global_settings.openAi_settings ??= DyNTS_OAI_global_settings;
90
-
91
- this.openai = new OpenAI(
92
- set?.config ??
93
- {
94
- organization: DyNTS_global_settings.env_settings.openAi.organization,
95
- apiKey: DyNTS_global_settings.env_settings.openAi.apiKey,
96
- project: DyNTS_global_settings.env_settings.openAi.project,
97
- }
98
- );
99
-
100
- this.defaultSettings = set?.defaultSettings ??
101
- DyNTS_OAI_global_settings.defaultSettings ??
102
- new DyFM_OAI_CallSettings();
103
- }
104
-
105
- /**
106
- * Inicializálja az OpenAI client-et a megadott config-gal
107
- *
108
- * Reinitializes the OpenAI client with the provided config
109
- */
110
- setup(config: DyFM_AI_Config): void {
111
- this.openai = new OpenAI(config);
112
- }
113
-
114
- /* readonly defaultLogReplacer: string = '...long-context...'; */
115
-
116
- //#region Ask Questions
117
-
118
- /**
119
- * Asks the AI to answer a yes/no question
120
- *
121
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.request} to ask the question,
122
- * and the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.upperCaseYes} to check the answer
123
- */
124
- async requestYesNo(
125
- set: DyFM_AI_Message_Input
126
- ): Promise<boolean> {
127
- set.message += this.predefinedRequests.yesNo.request;
128
-
129
- const answer = await this.requestSimpleMessage(set);
130
-
131
- return this.convertAnswerToBoolean(answer);
132
- }
133
- /** the exact same as {@link requestYesNo} */
134
- //yesNoQuestion = this.askYesNoQuestion;
135
-
136
- /**
137
- * Asks the AI to answer a percentage question
138
- *
139
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.percentageOnly} to ask the question
140
- */
141
- async requestPercentage(
142
- set: DyFM_AI_Message_Input
143
- ): Promise<number> {
144
- set.message += this.predefinedRequests.percentageOnly;
145
-
146
- const answer = await this.requestSimpleMessage(set);
147
-
148
- return this.convertAnswerToNumber(answer, set.message);
149
- }
150
- /** the exact same as {@link requestPercentage} */
151
- //percentageQuestion = this.askPercentageQuestion;
152
-
153
- /**
154
- * Asks the AI to select one of the options from the list
155
- *
156
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
157
- */
158
- /* async askSelectQuestion(
159
- set: DyFM_AI_GenericSelect_Input<string>
160
- ): Promise<string> {
161
- // replace the {{DyNTS_selectOptions}} with the list of options
162
- const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
163
- '{{DyNTS_selectOptions}}',
164
- this.getTextListAsText(set.selectFrom)
165
- );
166
- set.message += selectQuestionAddition;
167
-
168
- let answer = await this.requestSimpleMessage(set);
169
-
170
- answer = answer.toLocaleUpperCase();
171
-
172
- for (const item of set.selectFrom) {
173
- if (answer.includes(item.toLocaleUpperCase())) return item;
174
- }
175
-
176
- return null;
177
- } */
178
- /** the exact same as {@link askSelectQuestion} */
179
- //selectQuestion = this.askSelectQuestion;
180
-
181
- /**
182
- * Asks the AI to select one of the options from the list
183
- * Similar to {@link askSelectQuestion},
184
- * but with a more generic approach that can be used for objects
185
- *
186
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
187
- */
188
- async requestSelect<T>(
189
- set: DyFM_AI_GenericSelect_Input<T>
190
- ): Promise<T | { unparsableResult: string }> {
191
- const options: string[] = this.stringifySelectOptions(set.selectFrom);
192
- const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
193
- '{{DyNTS_selectOptions}}',
194
- this.getTextListAsText(options)
195
- );
196
- set.message += selectQuestionAddition;
197
-
198
- const answer = await this.requestSimpleMessage(set);
199
-
200
- return this.convertAnswerToSelectOption<T>(answer, set.message, set.selectFrom);
201
- }
202
- /** the exact same as {@link requestSelect} */
203
- //selectRequest = this.requestSelect;
204
-
205
- /**
206
- * Asks the AI to select one or more of the options from the list
207
- *
208
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
209
- */
210
- async requestMultiselect<T>(
211
- set: DyFM_AI_GenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
212
- ): Promise<T[] | { unparsableResult: string }> {
213
- const options: string[] = this.stringifySelectOptions(set.options);
214
- const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
215
- '{{DyNTS_selectOptions}}',
216
- this.getTextListAsText(options)
217
- );
218
- set.message += selectQuestionAddition;
219
-
220
- let answer = await this.requestSimpleMessage(set);
221
-
222
- answer = answer.toLocaleUpperCase();
223
-
224
- return this.convertAnswerToSelectOptions<T>(answer, set.message, set.options);
225
- /* const result: T[] = [];
226
-
227
- for (const item of options) {
228
- if (answer.includes(item.toLocaleUpperCase())) {
229
- const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(item);
230
- if ((parsedItem as { unparsableResult: string }).unparsableResult) {
231
- result.push(item as any);
232
- } else {
233
- result.push(parsedItem as T);
234
- }
235
-
236
- }
237
- }
238
-
239
- if (!result.length && !answer.trim().length) {
240
- return { unparsableResult: answer };
241
- }
242
-
243
- return result; */
244
- }
245
- /** the exact same as {@link askMultipleSelectQuestionWithOptions} */
246
- //multipleSelectQuestion = this.askMultipleSelectQuestionWithOptions;
247
-
248
- /**
249
- * Asks the AI to select one or more of the options from the list
250
- * Similar to {@link askMultipleSelectQuestionWithOptions},
251
- * but with a more generic approach that can be used for objects
252
- *
253
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
254
- */
255
- /* async requestMultiselect<T>(
256
- set: DyFM_AI_GenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
257
- ): Promise<T[]> {
258
- const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
259
- '{{DyNTS_selectOptions}}',
260
- this.getTextListAsText(set.options.map(item => `"${JSON.stringify(item)}"`))
261
- );
262
- set.message += selectQuestionAddition;
263
-
264
- const answer = await this.requestSimpleMessage(set);
265
-
266
- return DyFM_Object.safeParseList<T[]>(answer);
267
- } */
268
- /** the exact same as {@link requestMultipleSelect} */
269
- //multipleSelectRequest = this.requestMultipleSelect;
270
-
271
- /**
272
- * Asks the AI to answer a question that must result a JSON object
273
- *
274
- * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
275
- *
276
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequest} to ask the question
277
- *
278
- * (uses {@link DyFM_safeParseJSON})
279
- */
280
- async requestJSON<T = any>(
281
- set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
282
- ): Promise<T | { unparsableResult: string }> {
283
- set.message += this.predefinedRequests.jsonRequest;
284
-
285
- const answer = await this.requestSimpleMessage(set);
286
-
287
- return this.convertAnswerToJSON<T>(answer, set.message);
288
- }
289
- /** the exact same as {@link askJSONQuestion} */
290
- //jsonQuestion = this.askJSONQuestion;
291
-
292
- /**
293
- * Asks the AI to answer a question that must result a JSON object with specific key descriptions
294
- *
295
- * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
296
- *
297
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
298
- *
299
- * (uses {@link DyFM_safeParseJSON})
300
- */
301
- async requestJSONQuestionWithKeysDescription<T = any>(
302
- set: DyFM_AI_JSONKeysDescription_Input<DyFM_OAI_CallSettings>
303
- ): Promise<T | { unparsableResult: string }> {
304
- const jsonRequestWithKeysDescription = this.predefinedRequests.jsonRequestWithKeysDescription.replace(
305
- '{{DyNTS_jsonKeysDescription}}',
306
- set.keysDescription
307
- );
308
- set.message += jsonRequestWithKeysDescription;
309
-
310
- const answer = await this.requestSimpleMessage(set);
311
-
312
- return this.convertAnswerToJSON<T>(answer, set.message);
313
- }
314
- /** the exact same as {@link requestJSONQuestionWithKeysDescription} */
315
- //jsonQuestionWithKeysDescription = this.askJSONQuestionWithKeysDescription;
316
-
317
- /**
318
- * Asks the AI to answer a question that must result a JSON object with specific keys
319
- *
320
- * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
321
- *
322
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
323
- *
324
- * (uses {@link DyFM_safeParseJSON})
325
- */
326
- async requestJSONWithExactKeys<T = any>(
327
- set: DyFM_AI_JSONExactKeys_Input<DyFM_OAI_CallSettings>
328
- ): Promise<T | { unparsableResult: string }> {
329
- const jsonRequestWithExactKeys = this.predefinedRequests.jsonRequestWithExactKeys.replace(
330
- '{{DyNTS_jsonKeys}}',
331
- this.getTextListAsText(set.keys)
332
- );
333
- set.message += jsonRequestWithExactKeys;
334
-
335
- const answer = await this.requestSimpleMessage(set);
336
-
337
- return this.convertAnswerToJSON<T>(answer, set.message);
338
- }
339
- /** the exact same as {@link askJSONQuestionWithExactKeys} */
340
- //jsonQuestionWithExactKeys = this.askJSONQuestionWithExactKeys;
341
-
342
- /**
343
- * Asks the AI to answer a question that must result a list of strings
344
- *
345
- * If the answer is not a valid JSON list, it will return the answer as a single item in an array
346
- *
347
- * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.listRequest} to ask the question
348
- *
349
- * (uses {@link DyFM_Object.safeParseList})
350
- */
351
- /* async requestList(
352
- set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
353
- ): Promise<string[]> {
354
- set.message += this.predefinedRequests.listRequest;
355
-
356
- const answer = await this.requestSimpleMessage(set);
357
-
358
- return this.convertAnswerToList<string>(answer, set.message);
359
- } */
360
- /** the exact same as {@link askListQuestion} */
361
- //listQuestion = this.askListQuestion;
362
- /** the exact same as {@link askListQuestion} */
363
- //listRequest = this.askListQuestion;
364
-
365
- async requestList<T = any>(
366
- set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
367
- ): Promise<T[] | { unparsableResult: string }> {
368
- set.message += this.predefinedRequests.listRequest;
369
-
370
- const answer = await this.requestSimpleMessage(set);
371
-
372
- return this.convertAnswerToList<T>(answer, set.message);
373
- }
374
-
375
- /**
376
- * Asks the AI to answer a question
377
- *
378
- * Uses the {@link resolveSimpleUserMessage}
379
- */
380
- async requestSimpleMessage(
381
- set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
382
- ): Promise<string> {
383
- this.logQuestion(set);
384
-
385
- set.conversation ??= [];
386
- set.conversation.push({ role: DyFM_AI_MessageRole.user, content: set.message });
387
-
388
- const answer: string = await this.resolveMessage({
389
- ...set,
390
- conversation: set.conversation,
391
- getFullResponse: false,
392
- }) as string;
393
-
394
- this.logAnswer(answer);
395
-
396
- return answer;
397
- }
398
- /** the exact same as {@link requestSimpleMessage} */
399
- //answer = this.askQuestion;
400
- /** the exact same as {@link requestSimpleMessage} */
401
- //getQuestionAnswer = this.askQuestion;
402
- /** the exact same as {@link requestSimpleMessage} */
403
- //simpleQuestion = this.askQuestion;
404
- /** the exact same as {@link requestSimpleMessage} */
405
- //askSimpleQuestion = this.askQuestion;
406
-
407
- /**
408
- * Resolves a simple user message and returns the answer as string
409
- *
410
- * Uses the {@link resolveMessage}
411
- */
412
- /* async resolveSimpleUserMessage(
413
- set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
414
- ): Promise<string> {
415
- return this.resolveMessage({
416
- conversation: [{ role: DyFM_AI_MessageRole.user, content: set.message }],
417
- issuer: set.issuer ?? 'unknown',
418
- settings: set.settings ?? this.defaultSettings,
419
- getFullResponse: false,
420
- }) as Promise<string>;
421
- } */
422
- /** the exact same as {@link resolveSimpleUserMessage} */
423
- //simpleUserMessage = this.resolveSimpleUserMessage;
424
-
425
- //#endregion
426
-
427
- /**
428
- * Resolves a conversation
429
- *
430
- * Uses the {@link getMessageCreateInput}
431
- */
432
- async resolveMessage(
433
- set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
434
- /* {
435
- conversation: [{ role: DyFM_AI_MessageRole.user, content: set.message }],
436
- issuer: set.issuer ?? 'unknown',
437
- settings: set.settings ?? this.defaultSettings,
438
- getFullResponse: false,
439
- } */
440
- /* {
441
- conversation: DyFM_AI_Message[],
442
- issuer: string,
443
- settings?: DyFM_OAI_CallSettings,
444
- getFullResponse?: boolean
445
- } */
446
- ): Promise<string | ChatCompletion> {
447
- try {
448
- set.conversation.unshift(this.getDefaultSystemMessage(set.settings));
449
-
450
-
451
-
452
- const result: ChatCompletion = await this.openai.chat.completions.create(
453
- this.getMessageCreateInput(set)
454
- ) as ChatCompletion;
455
-
456
- if (set.getFullResponse) {
457
- return result;
458
- }
459
-
460
- return result.choices[0].message.content;
461
- } catch (error) {
462
- throw new DyFM_Error({
463
- ...this.getDefaultErrorSettings('resolveConversation', error, set.issuer),
464
-
465
- errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OLSB-RM0`,
466
- });
467
- }
468
- }
469
-
470
- /**
471
- * Creates a message create input
472
- *
473
- * Uses the {@link getDefaultSystemMessage}
474
- */
475
- protected getMessageCreateInput(
476
- set: {
477
- conversation: DyFM_AI_Message[],
478
- issuer: string,
479
- settings?: DyFM_OAI_CallSettings
480
- }
481
- ): ChatCompletionCreateParamsBase {
482
- try {
483
- const settings = set.settings ?? this.defaultSettings;
484
-
485
- const result: ChatCompletionCreateParamsBase = {
486
- model: settings?.useModel ?? this.defaultModel,
487
- messages: set.conversation as ChatCompletionMessageParam[],
488
- };
489
-
490
- result.temperature = DyFM_notNull(settings?.temperature) ?
491
- settings.temperature :
492
- this.defaultSettings.temperature;
493
-
494
- /* result.max_completion_tokens = DyFM_notNull(settings?.maxTokens) ?
495
- settings.maxTokens :
496
- this.defaultSettings.maxTokens; */
497
- result.max_completion_tokens = DyFM_notNull(settings?.maxTokens) ?
498
- settings.maxTokens :
499
- this.defaultSettings.maxTokens;
500
-
501
- result.top_p = DyFM_notNull(settings?.topP) ?
502
- settings.topP :
503
- this.defaultSettings.topP;
504
-
505
- result.frequency_penalty = DyFM_notNull(settings?.frequencyPenalty) ?
506
- settings.frequencyPenalty :
507
- this.defaultSettings.frequencyPenalty;
508
-
509
- result.presence_penalty = DyFM_notNull(settings?.presencePenalty) ?
510
- settings.presencePenalty :
511
- this.defaultSettings.presencePenalty;
512
-
513
- return result;
514
- } catch (error) {
515
- throw new DyFM_Error({
516
- ...this.getDefaultErrorSettings('getMessageCreateSettings', error, set.issuer),
517
-
518
- errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OLSB-RC0`,
519
- });
520
- }
521
- }
522
-
523
- /**
524
- * Teszteli a kapcsolatot az OpenAI API-val
525
- *
526
- * Tests the connection to OpenAI API
527
- */
528
- async testConnection(issuer: string): Promise<boolean> {
529
- try {
530
- await this.openai.models.list();
531
- return true;
532
- } catch (error) {
533
- DyFM_Log.error('DyNTS_OAI_LLM_ServiceBase', 'testConnection', 'Connection test failed', {
534
- error,
535
- issuer
536
- });
537
- return false;
538
- }
539
- }
540
-
541
- // async askJSONListQuestion(
542
- // question: string,
543
- // issuer: string,
544
- // settings?: DyFM_OAI_CallSettings,
545
- // debugLog?: boolean,
546
- // /** this is used to readably replace too long contents to eg '...' in logs */
547
- // replaceThisInLog?: string,
548
- // ): Promise<{ key: string, input: string }[]> {
549
- // question += this.predefinedRequests.jsonListRequest;
550
- //
551
- // const answer = await this.askQuestion(question, issuer, settings, debugLog, replaceThisInLog);
552
- //
553
- // return DyFM_Object.safeParseList<{ key: string, input: string }[]>(answer);
554
- // }
555
-
556
- //#region Tools
557
-
558
- /**
559
- * Logs the question if the debugLog is true
560
- */
561
- /* protected logQuestion(
562
- set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
563
- ): void {
564
- if (set.settings?.debugLog ?? this._debugLog) {
565
- console.log('\n - ', set.message);
566
- }
567
- } */
568
-
569
- /**
570
- * olvasható mondatszerű-listaszerű formába teszi a listaelemeket
571
- * pl.: ['a', 'b', 'c'] -> '"a", "b" or "c"'
572
- */
573
- /* getTextListAsText(list: string[]): string {
574
- list = list.filter(item => item?.trim()).map(item => `"${item}"`);
575
-
576
- //list = list.map(item => item.toLocaleLowerCase());
577
-
578
- list.push(list.pop() + ' or ' + list.pop());
579
-
580
- return list.join(', ');
581
- } */
582
-
583
- /* protected getDefaultSystemMessage(settings: DyFM_OAI_CallSettings): DyFM_AI_Message {
584
- return {
585
- role: DyFM_AI_MessageRole.system,
586
- content: settings?.systemPrompt || this.defaultSystemPrompt,
587
- };
588
- } */
589
-
590
- /* protected validateConversation(conversation: DyFM_AI_Message[]): void {
591
- conversation.forEach((message: DyFM_AI_Message, index: number) => {
592
- if (!message.role) {
593
- throw new DyFM_Error({
594
- message: `Message has no role at index ${index}`,
595
- additionalContent: {
596
- invalidMessage: message,
597
- conversation: conversation,
598
- }
599
- });
600
- }
601
-
602
- if (!message.content) {
603
- throw new DyFM_Error({
604
- message: `Message has no content at index ${index}`,
605
- additionalContent: {
606
- invalidMessage: message,
607
- conversation: conversation,
608
- }
609
- });
610
- }
611
- });
612
- } */
613
-
614
- /* protected getDefaultErrorSettings(
615
- fnName: string,
616
- error: DyFM_AnyError,
617
- issuer: string
618
- ): DyFM_Error_Settings {
619
- return {
620
- status: (error as DyFM_Error)?.___status ?? 500,
621
- message: (error as Error)?.message ??
622
- (error as DyFM_Error)?._message ??
623
- `${fnName} was UNSUCCESSFUL (${DyNTS_global_settings.systemShortCodeName})`,
624
- addECToUserMsg: !(error as DyFM_Error)?.__userMessage,
625
- userMessage: (error as DyFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,
626
- issuer: issuer,
627
- issuerService: this.constructor?.name,
628
- error: error,
629
- };
630
- } */
631
-
632
- //#endregion
633
-
634
- //#region Provider Methods (from DyNTS_AI_Provider_ServiceBase)
635
-
636
- //#endregion
637
-
638
- //#region Abstract LLM Methods (from DyNTS_AI_LLM_ServiceBase)
639
-
640
- /**
641
- * Meghívja az LLM-et system és user message-szel
642
- *
643
- * Calls the LLM with system and user messages
644
- */
645
- /* async callLLM(
646
- systemMessage: string,
647
- userMessage: string,
648
- settings?: DyFM_AI_CallSettings,
649
- issuer?: string
650
- ): Promise<string> {
651
- const result = await this.resolveMessage({
652
- conversation: [
653
- { role: DyFM_AI_MessageRole.system, content: systemMessage },
654
- { role: DyFM_AI_MessageRole.user, content: userMessage }
655
- ],
656
- issuer: issuer ?? 'system',
657
- settings: this.convertToOAISettings(settings),
658
- getFullResponse: false
659
- });
660
-
661
- if (typeof result === 'string') {
662
- return result;
663
- }
664
- return '';
665
- } */
666
-
667
- /**
668
- * Meghívja az LLM-et üzenet history-val
669
- *
670
- * Calls the LLM with message history
671
- */
672
- /* async callLLMWithHistory(
673
- messages: DyFM_AI_Message[],
674
- settings?: DyFM_AI_CallSettings,
675
- issuer?: string
676
- ): Promise<string> {
677
- const result = await this.resolveMessage({
678
- conversation: messages,
679
- issuer: issuer ?? 'system',
680
- settings: this.convertToOAISettings(settings),
681
- getFullResponse: false
682
- });
683
-
684
- if (typeof result === 'string') {
685
- return result;
686
- }
687
- return '';
688
- } */
689
-
690
- /**
691
- * Meghívja az LLM-et és visszaadja a raw response-t
692
- *
693
- * Calls the LLM and returns raw response
694
- */
695
- /* async callLLMRaw(
696
- messages: DyFM_AI_Message[],
697
- settings?: DyFM_AI_CallSettings,
698
- issuer?: string
699
- ): Promise<DyFM_AI_LLM_Response> {
700
- const result = await this.resolveMessage({
701
- conversation: messages,
702
- issuer: issuer ?? 'system',
703
- settings: this.convertToOAISettings(settings),
704
- getFullResponse: true
705
- }) as ChatCompletion;
706
-
707
- return {
708
- content: result.choices[0].message.content,
709
- usage: result.usage ? {
710
- promptTokens: result.usage.prompt_tokens,
711
- completionTokens: result.usage.completion_tokens,
712
- totalTokens: result.usage.total_tokens
713
- } : undefined,
714
- model: result.model,
715
- finishReason: result.choices[0].finish_reason,
716
- rawResponse: result
717
- };
718
- } */
719
-
720
- /**
721
- * Küld egy egyszerű üzenetet az LLM-nek
722
- *
723
- * Sends a simple message to the LLM
724
- */
725
- /* async sendMessage(set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>): Promise<string> {
726
- return await this.resolveSimpleUserMessage({
727
- message: set.message,
728
- issuer: set.issuer,
729
- settings: set.settings ? this.convertToOAISettings(set.settings) : undefined
730
- });
731
- } */
732
-
733
- /**
734
- * Kérdez egy kérdést és JSON választ vár exact keys-szel
735
- *
736
- * Asks a question and expects JSON response with exact keys
737
- */
738
- /* async requestJSONWithExactKeys<T = any>(
739
- set: DyFM_AI_JSONExactKeys_Input
740
- ): Promise<T> {
741
- const answer = await this.askJSONQuestionWithExactKeys({
742
- question: set.question,
743
- keys: set.keys,
744
- issuer: set.issuer,
745
- settings: set.settings ? this.convertToOAISettings(set.settings) : undefined,
746
- debugLog: set.debugLog,
747
- replaceThisInLog: set.replaceThisInLog
748
- });
749
-
750
- if ('unparsableResult' in answer) {
751
- throw new DyFM_Error({
752
- message: 'Invalid JSON response from AI',
753
- additionalContent: { answer },
754
- userMessage: 'Failed to parse AI response'
755
- });
756
- }
757
-
758
- return answer as T;
759
- } */
760
-
761
- /**
762
- * Kérdez egy kérdést és több választ vár
763
- *
764
- * Asks a question and expects multiple responses
765
- */
766
- /* async requestMultiselect<T = any>(
767
- set: DyFM_AI_GenericMultiSelect_Input<T>
768
- ): Promise<T[]> {
769
- const answer = await this.requestMultipleSelect({
770
- question: set.message,
771
- options: set.options,
772
- issuer: set.issuer,
773
- settings: set.settings ? this.convertToOAISettings(set.settings) : undefined,
774
- debugLog: set.debugLog,
775
- replaceThisInLog: set.replaceThisInLog
776
- });
777
-
778
- return answer as T[];
779
- } */
780
-
781
- /**
782
- * Konvertálja a generic AI settings-et OpenAI specifikus settings-re
783
- *
784
- * Converts generic AI settings to OpenAI-specific settings
785
- */
786
- /* private convertToOAISettings(settings?: DyFM_AI_CallSettings): DyFM_OAI_CallSettings {
787
- if (!settings) {
788
- return undefined;
789
- }
790
-
791
- const oaiSettings = new DyFM_OAI_CallSettings();
792
-
793
- if (settings.systemPrompt !== undefined) {
794
- oaiSettings.systemPrompt = settings.systemPrompt;
795
- }
796
-
797
- if (settings.useModel !== undefined) {
798
- oaiSettings.useModel = settings.useModel as DyFM_OAI_Model;
799
- }
800
-
801
- if (settings.project !== undefined) {
802
- oaiSettings.project = settings.project;
803
- }
804
-
805
- if (settings.debugLog !== undefined) {
806
- oaiSettings.debugLog = settings.debugLog;
807
- }
808
-
809
- if (settings.temperature !== undefined) {
810
- oaiSettings.temperature = settings.temperature;
811
- }
812
-
813
- if (settings.maxTokens !== undefined) {
814
- oaiSettings.maxTokens = settings.maxTokens;
815
- }
816
-
817
- if (settings.topP !== undefined) {
818
- oaiSettings.topP = settings.topP;
819
- }
820
-
821
- if (settings.frequencyPenalty !== undefined) {
822
- oaiSettings.frequencyPenalty = settings.frequencyPenalty;
823
- }
824
-
825
- if (settings.presencePenalty !== undefined) {
826
- oaiSettings.presencePenalty = settings.presencePenalty;
827
- }
828
-
829
- return oaiSettings;
830
- } */
831
-
832
- //#endregion
833
- }
1
+ import { OpenAI } from 'openai';
2
+
3
+ import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
4
+ import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_Log, DyFM_notNull, DyFM_Object } from '@futdevpro/fsm-dynamo';
5
+ import {
6
+ DyFM_AI_Message,
7
+ DyFM_AI_MessageRole,
8
+ DyFM_AI_Provider,
9
+ DyFM_AI_ProviderCapabilities,
10
+ DyFM_AI_CallSettings,
11
+ DyFM_AI_Config,
12
+ DyFM_AI_LLM_Response
13
+ } from '@futdevpro/fsm-dynamo/ai';
14
+
15
+ import { DyNTS_global_settings } from '../../../../../_collections/global-settings.const';
16
+ import { ChatCompletion } from 'openai/resources';
17
+ import { ChatCompletionCreateParamsBase, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
18
+ import { DyNTS_OAI_LLM_Predefined_Requests } from '../_models/interfaces/oai-llm-predefined-requests.interface';
19
+ import { DyNTS_OAI_global_settings } from '../_collections/oai-global-settings.const';
20
+ import { DyNTS_OAI_LLMDefaultPredefined_Requests } from '../_collections/oai-llm-predefined-requests.conts';
21
+ import { DyNTS_AI_LLM_ServiceBase } from '../../../_services/ai-llm.service-base';
22
+ import {
23
+ DyFM_AI_Message_Input,
24
+ DyFM_AI_GenericSelect_Input,
25
+ DyFM_AI_GenericMultiSelect_Input,
26
+ DyFM_AI_JSONKeysDescription_Input,
27
+ DyFM_AI_JSONExactKeys_Input,
28
+ DyFM_AI_MultiSelect_Input,
29
+ DyFM_AI_ConversationBase_Input
30
+ } from '../../../_models/ai-input-interfaces';
31
+
32
+
33
+ /**
34
+ * {
35
+ * organization: 'org-XY',
36
+ * apiKey: 'sk-XY',
37
+ * project: 'proj_XY',
38
+ * }
39
+ */
40
+
41
+ // Di Dictionary DiModel DiEz DiAz
42
+
43
+ export class DyNTS_OAI_LLM_ServiceBase extends DyNTS_AI_LLM_ServiceBase {
44
+
45
+ /* readonly defaultErrorUserMsg: string =
46
+ `We encountered an unhandled Control Service Error, ` +
47
+ `\nplease contact the responsible development team.`; */
48
+
49
+ openai: OpenAI;
50
+
51
+ readonly defaultSettings: DyFM_OAI_CallSettings;
52
+
53
+ // Provider properties from DyNTS_AI_Provider_ServiceBase
54
+ readonly aiProvider: DyFM_AI_Provider = DyFM_AI_Provider.OpenAI;
55
+
56
+ readonly capabilities: DyFM_AI_ProviderCapabilities = {
57
+ chat: true,
58
+ embeddings: true,
59
+ imageGeneration: true,
60
+ vision: true,
61
+ audioGeneration: true,
62
+ audioAnalysis: true,
63
+ functionCalling: true,
64
+ streaming: true,
65
+ batchOperations: true,
66
+ maxContextLength: 128000,
67
+ supportedModelTypes: ['gpt-4o', 'gpt-4o-mini', 'text-embedding-3-large', 'text-embedding-3-small']
68
+ };
69
+
70
+ /* get _debugLog(): boolean {
71
+ return this.defaultSettings.debugLog;
72
+ } */
73
+
74
+ /* get defaultSystemPrompt(): string {
75
+ return this.defaultSettings.systemPrompt;
76
+ } */
77
+
78
+ override get defaultModel(): DyFM_OAI_Model | string {
79
+ return this.defaultSettings.useModel;
80
+ }
81
+
82
+ predefinedRequests: DyNTS_OAI_LLM_Predefined_Requests = DyNTS_OAI_LLMDefaultPredefined_Requests;
83
+
84
+ constructor(
85
+ set?: DyFM_OAI_Settings
86
+ ) {
87
+ super();
88
+
89
+ DyNTS_global_settings.openAi_settings ??= DyNTS_OAI_global_settings;
90
+
91
+ this.openai = new OpenAI(
92
+ set?.config ??
93
+ {
94
+ organization: DyNTS_global_settings.env_settings.openAi.organization,
95
+ apiKey: DyNTS_global_settings.env_settings.openAi.apiKey,
96
+ project: DyNTS_global_settings.env_settings.openAi.project,
97
+ }
98
+ );
99
+
100
+ this.defaultSettings = set?.defaultSettings ??
101
+ DyNTS_OAI_global_settings.defaultSettings ??
102
+ new DyFM_OAI_CallSettings();
103
+ }
104
+
105
+ /**
106
+ * Inicializálja az OpenAI client-et a megadott config-gal
107
+ *
108
+ * Reinitializes the OpenAI client with the provided config
109
+ */
110
+ setup(config: DyFM_AI_Config): void {
111
+ this.openai = new OpenAI(config);
112
+ }
113
+
114
+ /* readonly defaultLogReplacer: string = '...long-context...'; */
115
+
116
+ //#region Ask Questions
117
+
118
+ /**
119
+ * Asks the AI to answer a yes/no question
120
+ *
121
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.request} to ask the question,
122
+ * and the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.upperCaseYes} to check the answer
123
+ */
124
+ async requestYesNo(
125
+ set: DyFM_AI_Message_Input
126
+ ): Promise<boolean> {
127
+ set.message += this.predefinedRequests.yesNo.request;
128
+
129
+ const answer = await this.requestSimpleMessage(set);
130
+
131
+ return this.convertAnswerToBoolean(answer);
132
+ }
133
+ /** the exact same as {@link requestYesNo} */
134
+ //yesNoQuestion = this.askYesNoQuestion;
135
+
136
+ /**
137
+ * Asks the AI to answer a percentage question
138
+ *
139
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.percentageOnly} to ask the question
140
+ */
141
+ async requestPercentage(
142
+ set: DyFM_AI_Message_Input
143
+ ): Promise<number> {
144
+ set.message += this.predefinedRequests.percentageOnly;
145
+
146
+ const answer = await this.requestSimpleMessage(set);
147
+
148
+ return this.convertAnswerToNumber(answer, set.message);
149
+ }
150
+ /** the exact same as {@link requestPercentage} */
151
+ //percentageQuestion = this.askPercentageQuestion;
152
+
153
+ /**
154
+ * Asks the AI to select one of the options from the list
155
+ *
156
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
157
+ */
158
+ /* async askSelectQuestion(
159
+ set: DyFM_AI_GenericSelect_Input<string>
160
+ ): Promise<string> {
161
+ // replace the {{DyNTS_selectOptions}} with the list of options
162
+ const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
163
+ '{{DyNTS_selectOptions}}',
164
+ this.getTextListAsText(set.selectFrom)
165
+ );
166
+ set.message += selectQuestionAddition;
167
+
168
+ let answer = await this.requestSimpleMessage(set);
169
+
170
+ answer = answer.toLocaleUpperCase();
171
+
172
+ for (const item of set.selectFrom) {
173
+ if (answer.includes(item.toLocaleUpperCase())) return item;
174
+ }
175
+
176
+ return null;
177
+ } */
178
+ /** the exact same as {@link askSelectQuestion} */
179
+ //selectQuestion = this.askSelectQuestion;
180
+
181
+ /**
182
+ * Asks the AI to select one of the options from the list
183
+ * Similar to {@link askSelectQuestion},
184
+ * but with a more generic approach that can be used for objects
185
+ *
186
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
187
+ */
188
+ async requestSelect<T>(
189
+ set: DyFM_AI_GenericSelect_Input<T>
190
+ ): Promise<T | { unparsableResult: string }> {
191
+ const options: string[] = this.stringifySelectOptions(set.selectFrom);
192
+ const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
193
+ '{{DyNTS_selectOptions}}',
194
+ this.getTextListAsText(options)
195
+ );
196
+ set.message += selectQuestionAddition;
197
+
198
+ const answer = await this.requestSimpleMessage(set);
199
+
200
+ return this.convertAnswerToSelectOption<T>(answer, set.message, set.selectFrom);
201
+ }
202
+ /** the exact same as {@link requestSelect} */
203
+ //selectRequest = this.requestSelect;
204
+
205
+ /**
206
+ * Asks the AI to select one or more of the options from the list
207
+ *
208
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
209
+ */
210
+ async requestMultiselect<T>(
211
+ set: DyFM_AI_GenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
212
+ ): Promise<T[] | { unparsableResult: string }> {
213
+ const options: string[] = this.stringifySelectOptions(set.options);
214
+ const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
215
+ '{{DyNTS_selectOptions}}',
216
+ this.getTextListAsText(options)
217
+ );
218
+ set.message += selectQuestionAddition;
219
+
220
+ let answer = await this.requestSimpleMessage(set);
221
+
222
+ answer = answer.toLocaleUpperCase();
223
+
224
+ return this.convertAnswerToSelectOptions<T>(answer, set.message, set.options);
225
+ /* const result: T[] = [];
226
+
227
+ for (const item of options) {
228
+ if (answer.includes(item.toLocaleUpperCase())) {
229
+ const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(item);
230
+ if ((parsedItem as { unparsableResult: string }).unparsableResult) {
231
+ result.push(item as any);
232
+ } else {
233
+ result.push(parsedItem as T);
234
+ }
235
+
236
+ }
237
+ }
238
+
239
+ if (!result.length && !answer.trim().length) {
240
+ return { unparsableResult: answer };
241
+ }
242
+
243
+ return result; */
244
+ }
245
+ /** the exact same as {@link askMultipleSelectQuestionWithOptions} */
246
+ //multipleSelectQuestion = this.askMultipleSelectQuestionWithOptions;
247
+
248
+ /**
249
+ * Asks the AI to select one or more of the options from the list
250
+ * Similar to {@link askMultipleSelectQuestionWithOptions},
251
+ * but with a more generic approach that can be used for objects
252
+ *
253
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
254
+ */
255
+ /* async requestMultiselect<T>(
256
+ set: DyFM_AI_GenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
257
+ ): Promise<T[]> {
258
+ const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
259
+ '{{DyNTS_selectOptions}}',
260
+ this.getTextListAsText(set.options.map(item => `"${JSON.stringify(item)}"`))
261
+ );
262
+ set.message += selectQuestionAddition;
263
+
264
+ const answer = await this.requestSimpleMessage(set);
265
+
266
+ return DyFM_Object.safeParseList<T[]>(answer);
267
+ } */
268
+ /** the exact same as {@link requestMultipleSelect} */
269
+ //multipleSelectRequest = this.requestMultipleSelect;
270
+
271
+ /**
272
+ * Asks the AI to answer a question that must result a JSON object
273
+ *
274
+ * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
275
+ *
276
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequest} to ask the question
277
+ *
278
+ * (uses {@link DyFM_safeParseJSON})
279
+ */
280
+ async requestJSON<T = any>(
281
+ set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
282
+ ): Promise<T | { unparsableResult: string }> {
283
+ set.message += this.predefinedRequests.jsonRequest;
284
+
285
+ const answer = await this.requestSimpleMessage(set);
286
+
287
+ return this.convertAnswerToJSON<T>(answer, set.message);
288
+ }
289
+ /** the exact same as {@link askJSONQuestion} */
290
+ //jsonQuestion = this.askJSONQuestion;
291
+
292
+ /**
293
+ * Asks the AI to answer a question that must result a JSON object with specific key descriptions
294
+ *
295
+ * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
296
+ *
297
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
298
+ *
299
+ * (uses {@link DyFM_safeParseJSON})
300
+ */
301
+ async requestJSONQuestionWithKeysDescription<T = any>(
302
+ set: DyFM_AI_JSONKeysDescription_Input<DyFM_OAI_CallSettings>
303
+ ): Promise<T | { unparsableResult: string }> {
304
+ const jsonRequestWithKeysDescription = this.predefinedRequests.jsonRequestWithKeysDescription.replace(
305
+ '{{DyNTS_jsonKeysDescription}}',
306
+ set.keysDescription
307
+ );
308
+ set.message += jsonRequestWithKeysDescription;
309
+
310
+ const answer = await this.requestSimpleMessage(set);
311
+
312
+ return this.convertAnswerToJSON<T>(answer, set.message);
313
+ }
314
+ /** the exact same as {@link requestJSONQuestionWithKeysDescription} */
315
+ //jsonQuestionWithKeysDescription = this.askJSONQuestionWithKeysDescription;
316
+
317
+ /**
318
+ * Asks the AI to answer a question that must result a JSON object with specific keys
319
+ *
320
+ * If the answer is not a valid JSON object, it will return { unparsableResult: answer }
321
+ *
322
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
323
+ *
324
+ * (uses {@link DyFM_safeParseJSON})
325
+ */
326
+ async requestJSONWithExactKeys<T = any>(
327
+ set: DyFM_AI_JSONExactKeys_Input<DyFM_OAI_CallSettings>
328
+ ): Promise<T | { unparsableResult: string }> {
329
+ const jsonRequestWithExactKeys = this.predefinedRequests.jsonRequestWithExactKeys.replace(
330
+ '{{DyNTS_jsonKeys}}',
331
+ this.getTextListAsText(set.keys)
332
+ );
333
+ set.message += jsonRequestWithExactKeys;
334
+
335
+ const answer = await this.requestSimpleMessage(set);
336
+
337
+ return this.convertAnswerToJSON<T>(answer, set.message);
338
+ }
339
+ /** the exact same as {@link askJSONQuestionWithExactKeys} */
340
+ //jsonQuestionWithExactKeys = this.askJSONQuestionWithExactKeys;
341
+
342
+ /**
343
+ * Asks the AI to answer a question that must result a list of strings
344
+ *
345
+ * If the answer is not a valid JSON list, it will return the answer as a single item in an array
346
+ *
347
+ * Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.listRequest} to ask the question
348
+ *
349
+ * (uses {@link DyFM_Object.safeParseList})
350
+ */
351
+ /* async requestList(
352
+ set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
353
+ ): Promise<string[]> {
354
+ set.message += this.predefinedRequests.listRequest;
355
+
356
+ const answer = await this.requestSimpleMessage(set);
357
+
358
+ return this.convertAnswerToList<string>(answer, set.message);
359
+ } */
360
+ /** the exact same as {@link askListQuestion} */
361
+ //listQuestion = this.askListQuestion;
362
+ /** the exact same as {@link askListQuestion} */
363
+ //listRequest = this.askListQuestion;
364
+
365
+ async requestList<T = any>(
366
+ set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
367
+ ): Promise<T[] | { unparsableResult: string }> {
368
+ set.message += this.predefinedRequests.listRequest;
369
+
370
+ const answer = await this.requestSimpleMessage(set);
371
+
372
+ return this.convertAnswerToList<T>(answer, set.message);
373
+ }
374
+
375
+ /**
376
+ * Asks the AI to answer a question
377
+ *
378
+ * Uses the {@link resolveSimpleUserMessage}
379
+ */
380
+ async requestSimpleMessage(
381
+ set: DyFM_AI_Message_Input<DyFM_OAI_CallSettings>
382
+ ): Promise<string> {
383
+ this.logQuestion(set);
384
+
385
+ set.conversation ??= [];
386
+ set.conversation.push({ role: DyFM_AI_MessageRole.user, content: set.message });
387
+
388
+ const answer: string = await this.resolveMessage({
389
+ ...set,
390
+ conversation: set.conversation,
391
+ getFullResponse: false,
392
+ }) as string;
393
+
394
+ this.logAnswer(answer);
395
+
396
+ return answer;
397
+ }
398
+ /** the exact same as {@link requestSimpleMessage} */
399
+ //answer = this.askQuestion;
400
+ /** the exact same as {@link requestSimpleMessage} */
401
+ //getQuestionAnswer = this.askQuestion;
402
+ /** the exact same as {@link requestSimpleMessage} */
403
+ //simpleQuestion = this.askQuestion;
404
+ /** the exact same as {@link requestSimpleMessage} */
405
+ //askSimpleQuestion = this.askQuestion;
406
+
407
+ /**
408
+ * Resolves a simple user message and returns the answer as string
409
+ *
410
+ * Uses the {@link resolveMessage}
411
+ */
412
+ /* async resolveSimpleUserMessage(
413
+ set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
414
+ ): Promise<string> {
415
+ return this.resolveMessage({
416
+ conversation: [{ role: DyFM_AI_MessageRole.user, content: set.message }],
417
+ issuer: set.issuer ?? 'unknown',
418
+ settings: set.settings ?? this.defaultSettings,
419
+ getFullResponse: false,
420
+ }) as Promise<string>;
421
+ } */
422
+ /** the exact same as {@link resolveSimpleUserMessage} */
423
+ //simpleUserMessage = this.resolveSimpleUserMessage;
424
+
425
+ //#endregion
426
+
427
+ /**
428
+ * Resolves a conversation
429
+ *
430
+ * Uses the {@link getMessageCreateInput}
431
+ */
432
+ async resolveMessage(
433
+ set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
434
+ /* {
435
+ conversation: [{ role: DyFM_AI_MessageRole.user, content: set.message }],
436
+ issuer: set.issuer ?? 'unknown',
437
+ settings: set.settings ?? this.defaultSettings,
438
+ getFullResponse: false,
439
+ } */
440
+ /* {
441
+ conversation: DyFM_AI_Message[],
442
+ issuer: string,
443
+ settings?: DyFM_OAI_CallSettings,
444
+ getFullResponse?: boolean
445
+ } */
446
+ ): Promise<string | ChatCompletion> {
447
+ try {
448
+ set.conversation.unshift(this.getDefaultSystemMessage(set.settings));
449
+
450
+
451
+
452
+ const result: ChatCompletion = await this.openai.chat.completions.create(
453
+ this.getMessageCreateInput(set)
454
+ ) as ChatCompletion;
455
+
456
+ if (set.getFullResponse) {
457
+ return result;
458
+ }
459
+
460
+ return result.choices[0].message.content;
461
+ } catch (error) {
462
+ throw new DyFM_Error({
463
+ ...this.getDefaultErrorSettings('resolveConversation', error, set.issuer),
464
+
465
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OLSB-RM0`,
466
+ });
467
+ }
468
+ }
469
+
470
+ /**
471
+ * Creates a message create input
472
+ *
473
+ * Uses the {@link getDefaultSystemMessage}
474
+ */
475
+ protected getMessageCreateInput(
476
+ set: {
477
+ conversation: DyFM_AI_Message[],
478
+ issuer: string,
479
+ settings?: DyFM_OAI_CallSettings
480
+ }
481
+ ): ChatCompletionCreateParamsBase {
482
+ try {
483
+ const settings = set.settings ?? this.defaultSettings;
484
+
485
+ const result: ChatCompletionCreateParamsBase = {
486
+ model: settings?.useModel ?? this.defaultModel,
487
+ messages: set.conversation as ChatCompletionMessageParam[],
488
+ };
489
+
490
+ result.temperature = DyFM_notNull(settings?.temperature) ?
491
+ settings.temperature :
492
+ this.defaultSettings.temperature;
493
+
494
+ /* result.max_completion_tokens = DyFM_notNull(settings?.maxTokens) ?
495
+ settings.maxTokens :
496
+ this.defaultSettings.maxTokens; */
497
+ result.max_completion_tokens = DyFM_notNull(settings?.maxTokens) ?
498
+ settings.maxTokens :
499
+ this.defaultSettings.maxTokens;
500
+
501
+ result.top_p = DyFM_notNull(settings?.topP) ?
502
+ settings.topP :
503
+ this.defaultSettings.topP;
504
+
505
+ result.frequency_penalty = DyFM_notNull(settings?.frequencyPenalty) ?
506
+ settings.frequencyPenalty :
507
+ this.defaultSettings.frequencyPenalty;
508
+
509
+ result.presence_penalty = DyFM_notNull(settings?.presencePenalty) ?
510
+ settings.presencePenalty :
511
+ this.defaultSettings.presencePenalty;
512
+
513
+ return result;
514
+ } catch (error) {
515
+ throw new DyFM_Error({
516
+ ...this.getDefaultErrorSettings('getMessageCreateSettings', error, set.issuer),
517
+
518
+ errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OLSB-RC0`,
519
+ });
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Teszteli a kapcsolatot az OpenAI API-val
525
+ *
526
+ * Tests the connection to OpenAI API
527
+ */
528
+ async testConnection(issuer: string): Promise<boolean> {
529
+ try {
530
+ await this.openai.models.list();
531
+ return true;
532
+ } catch (error) {
533
+ DyFM_Log.error('DyNTS_OAI_LLM_ServiceBase', 'testConnection', 'Connection test failed', {
534
+ error,
535
+ issuer
536
+ });
537
+ return false;
538
+ }
539
+ }
540
+
541
+ // async askJSONListQuestion(
542
+ // question: string,
543
+ // issuer: string,
544
+ // settings?: DyFM_OAI_CallSettings,
545
+ // debugLog?: boolean,
546
+ // /** this is used to readably replace too long contents to eg '...' in logs */
547
+ // replaceThisInLog?: string,
548
+ // ): Promise<{ key: string, input: string }[]> {
549
+ // question += this.predefinedRequests.jsonListRequest;
550
+ //
551
+ // const answer = await this.askQuestion(question, issuer, settings, debugLog, replaceThisInLog);
552
+ //
553
+ // return DyFM_Object.safeParseList<{ key: string, input: string }[]>(answer);
554
+ // }
555
+
556
+ //#region Tools
557
+
558
+ /**
559
+ * Logs the question if the debugLog is true
560
+ */
561
+ /* protected logQuestion(
562
+ set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>
563
+ ): void {
564
+ if (set.settings?.debugLog ?? this._debugLog) {
565
+ console.log('\n - ', set.message);
566
+ }
567
+ } */
568
+
569
+ /**
570
+ * olvasható mondatszerű-listaszerű formába teszi a listaelemeket
571
+ * pl.: ['a', 'b', 'c'] -> '"a", "b" or "c"'
572
+ */
573
+ /* getTextListAsText(list: string[]): string {
574
+ list = list.filter(item => item?.trim()).map(item => `"${item}"`);
575
+
576
+ //list = list.map(item => item.toLocaleLowerCase());
577
+
578
+ list.push(list.pop() + ' or ' + list.pop());
579
+
580
+ return list.join(', ');
581
+ } */
582
+
583
+ /* protected getDefaultSystemMessage(settings: DyFM_OAI_CallSettings): DyFM_AI_Message {
584
+ return {
585
+ role: DyFM_AI_MessageRole.system,
586
+ content: settings?.systemPrompt || this.defaultSystemPrompt,
587
+ };
588
+ } */
589
+
590
+ /* protected validateConversation(conversation: DyFM_AI_Message[]): void {
591
+ conversation.forEach((message: DyFM_AI_Message, index: number) => {
592
+ if (!message.role) {
593
+ throw new DyFM_Error({
594
+ message: `Message has no role at index ${index}`,
595
+ additionalContent: {
596
+ invalidMessage: message,
597
+ conversation: conversation,
598
+ }
599
+ });
600
+ }
601
+
602
+ if (!message.content) {
603
+ throw new DyFM_Error({
604
+ message: `Message has no content at index ${index}`,
605
+ additionalContent: {
606
+ invalidMessage: message,
607
+ conversation: conversation,
608
+ }
609
+ });
610
+ }
611
+ });
612
+ } */
613
+
614
+ /* protected getDefaultErrorSettings(
615
+ fnName: string,
616
+ error: DyFM_AnyError,
617
+ issuer: string
618
+ ): DyFM_Error_Settings {
619
+ return {
620
+ status: (error as DyFM_Error)?.___status ?? 500,
621
+ message: (error as Error)?.message ??
622
+ (error as DyFM_Error)?._message ??
623
+ `${fnName} was UNSUCCESSFUL (${DyNTS_global_settings.systemShortCodeName})`,
624
+ addECToUserMsg: !(error as DyFM_Error)?.__userMessage,
625
+ userMessage: (error as DyFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,
626
+ issuer: issuer,
627
+ issuerService: this.constructor?.name,
628
+ error: error,
629
+ };
630
+ } */
631
+
632
+ //#endregion
633
+
634
+ //#region Provider Methods (from DyNTS_AI_Provider_ServiceBase)
635
+
636
+ //#endregion
637
+
638
+ //#region Abstract LLM Methods (from DyNTS_AI_LLM_ServiceBase)
639
+
640
+ /**
641
+ * Meghívja az LLM-et system és user message-szel
642
+ *
643
+ * Calls the LLM with system and user messages
644
+ */
645
+ /* async callLLM(
646
+ systemMessage: string,
647
+ userMessage: string,
648
+ settings?: DyFM_AI_CallSettings,
649
+ issuer?: string
650
+ ): Promise<string> {
651
+ const result = await this.resolveMessage({
652
+ conversation: [
653
+ { role: DyFM_AI_MessageRole.system, content: systemMessage },
654
+ { role: DyFM_AI_MessageRole.user, content: userMessage }
655
+ ],
656
+ issuer: issuer ?? 'system',
657
+ settings: this.convertToOAISettings(settings),
658
+ getFullResponse: false
659
+ });
660
+
661
+ if (typeof result === 'string') {
662
+ return result;
663
+ }
664
+ return '';
665
+ } */
666
+
667
+ /**
668
+ * Meghívja az LLM-et üzenet history-val
669
+ *
670
+ * Calls the LLM with message history
671
+ */
672
+ /* async callLLMWithHistory(
673
+ messages: DyFM_AI_Message[],
674
+ settings?: DyFM_AI_CallSettings,
675
+ issuer?: string
676
+ ): Promise<string> {
677
+ const result = await this.resolveMessage({
678
+ conversation: messages,
679
+ issuer: issuer ?? 'system',
680
+ settings: this.convertToOAISettings(settings),
681
+ getFullResponse: false
682
+ });
683
+
684
+ if (typeof result === 'string') {
685
+ return result;
686
+ }
687
+ return '';
688
+ } */
689
+
690
+ /**
691
+ * Meghívja az LLM-et és visszaadja a raw response-t
692
+ *
693
+ * Calls the LLM and returns raw response
694
+ */
695
+ /* async callLLMRaw(
696
+ messages: DyFM_AI_Message[],
697
+ settings?: DyFM_AI_CallSettings,
698
+ issuer?: string
699
+ ): Promise<DyFM_AI_LLM_Response> {
700
+ const result = await this.resolveMessage({
701
+ conversation: messages,
702
+ issuer: issuer ?? 'system',
703
+ settings: this.convertToOAISettings(settings),
704
+ getFullResponse: true
705
+ }) as ChatCompletion;
706
+
707
+ return {
708
+ content: result.choices[0].message.content,
709
+ usage: result.usage ? {
710
+ promptTokens: result.usage.prompt_tokens,
711
+ completionTokens: result.usage.completion_tokens,
712
+ totalTokens: result.usage.total_tokens
713
+ } : undefined,
714
+ model: result.model,
715
+ finishReason: result.choices[0].finish_reason,
716
+ rawResponse: result
717
+ };
718
+ } */
719
+
720
+ /**
721
+ * Küld egy egyszerű üzenetet az LLM-nek
722
+ *
723
+ * Sends a simple message to the LLM
724
+ */
725
+ /* async sendMessage(set: DyFM_AI_Base_Input<DyFM_OAI_CallSettings>): Promise<string> {
726
+ return await this.resolveSimpleUserMessage({
727
+ message: set.message,
728
+ issuer: set.issuer,
729
+ settings: set.settings ? this.convertToOAISettings(set.settings) : undefined
730
+ });
731
+ } */
732
+
733
+ /**
734
+ * Kérdez egy kérdést és JSON választ vár exact keys-szel
735
+ *
736
+ * Asks a question and expects JSON response with exact keys
737
+ */
738
+ /* async requestJSONWithExactKeys<T = any>(
739
+ set: DyFM_AI_JSONExactKeys_Input
740
+ ): Promise<T> {
741
+ const answer = await this.askJSONQuestionWithExactKeys({
742
+ question: set.question,
743
+ keys: set.keys,
744
+ issuer: set.issuer,
745
+ settings: set.settings ? this.convertToOAISettings(set.settings) : undefined,
746
+ debugLog: set.debugLog,
747
+ replaceThisInLog: set.replaceThisInLog
748
+ });
749
+
750
+ if ('unparsableResult' in answer) {
751
+ throw new DyFM_Error({
752
+ message: 'Invalid JSON response from AI',
753
+ additionalContent: { answer },
754
+ userMessage: 'Failed to parse AI response'
755
+ });
756
+ }
757
+
758
+ return answer as T;
759
+ } */
760
+
761
+ /**
762
+ * Kérdez egy kérdést és több választ vár
763
+ *
764
+ * Asks a question and expects multiple responses
765
+ */
766
+ /* async requestMultiselect<T = any>(
767
+ set: DyFM_AI_GenericMultiSelect_Input<T>
768
+ ): Promise<T[]> {
769
+ const answer = await this.requestMultipleSelect({
770
+ question: set.message,
771
+ options: set.options,
772
+ issuer: set.issuer,
773
+ settings: set.settings ? this.convertToOAISettings(set.settings) : undefined,
774
+ debugLog: set.debugLog,
775
+ replaceThisInLog: set.replaceThisInLog
776
+ });
777
+
778
+ return answer as T[];
779
+ } */
780
+
781
+ /**
782
+ * Konvertálja a generic AI settings-et OpenAI specifikus settings-re
783
+ *
784
+ * Converts generic AI settings to OpenAI-specific settings
785
+ */
786
+ /* private convertToOAISettings(settings?: DyFM_AI_CallSettings): DyFM_OAI_CallSettings {
787
+ if (!settings) {
788
+ return undefined;
789
+ }
790
+
791
+ const oaiSettings = new DyFM_OAI_CallSettings();
792
+
793
+ if (settings.systemPrompt !== undefined) {
794
+ oaiSettings.systemPrompt = settings.systemPrompt;
795
+ }
796
+
797
+ if (settings.useModel !== undefined) {
798
+ oaiSettings.useModel = settings.useModel as DyFM_OAI_Model;
799
+ }
800
+
801
+ if (settings.project !== undefined) {
802
+ oaiSettings.project = settings.project;
803
+ }
804
+
805
+ if (settings.debugLog !== undefined) {
806
+ oaiSettings.debugLog = settings.debugLog;
807
+ }
808
+
809
+ if (settings.temperature !== undefined) {
810
+ oaiSettings.temperature = settings.temperature;
811
+ }
812
+
813
+ if (settings.maxTokens !== undefined) {
814
+ oaiSettings.maxTokens = settings.maxTokens;
815
+ }
816
+
817
+ if (settings.topP !== undefined) {
818
+ oaiSettings.topP = settings.topP;
819
+ }
820
+
821
+ if (settings.frequencyPenalty !== undefined) {
822
+ oaiSettings.frequencyPenalty = settings.frequencyPenalty;
823
+ }
824
+
825
+ if (settings.presencePenalty !== undefined) {
826
+ oaiSettings.presencePenalty = settings.presencePenalty;
827
+ }
828
+
829
+ return oaiSettings;
830
+ } */
831
+
832
+ //#endregion
833
+ }