@goscribe/server 1.3.3 → 1.5.0

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 (378) hide show
  1. package/.env.example +12 -0
  2. package/.vscode/settings.json +3 -0
  3. package/REFACTOR_NOTES.md +60 -0
  4. package/TESTING_PROMPT.md +225 -0
  5. package/dist/controllers/admin.controller.d.ts +715 -0
  6. package/dist/controllers/admin.controller.js +9 -0
  7. package/dist/controllers/annotations.controller.d.ts +439 -0
  8. package/dist/controllers/annotations.controller.js +9 -0
  9. package/dist/controllers/app-router.controller.d.ts +3011 -0
  10. package/dist/controllers/app-router.controller.js +38 -0
  11. package/dist/controllers/app-router.controller.test.d.ts +1 -0
  12. package/dist/controllers/app-router.controller.test.js +36 -0
  13. package/dist/controllers/auth.controller.d.ts +323 -0
  14. package/dist/controllers/auth.controller.js +9 -0
  15. package/dist/controllers/base.controller.d.ts +4 -0
  16. package/dist/controllers/base.controller.js +5 -0
  17. package/dist/controllers/chat.controller.d.ts +341 -0
  18. package/dist/controllers/chat.controller.js +9 -0
  19. package/dist/controllers/copilot.controller.d.ts +397 -0
  20. package/dist/controllers/copilot.controller.js +9 -0
  21. package/dist/controllers/flashcards.controller.d.ts +651 -0
  22. package/dist/controllers/flashcards.controller.js +9 -0
  23. package/dist/controllers/members.controller.d.ts +339 -0
  24. package/dist/controllers/members.controller.js +9 -0
  25. package/dist/controllers/notifications.controller.d.ts +199 -0
  26. package/dist/controllers/notifications.controller.js +9 -0
  27. package/dist/controllers/payment.controller.d.ts +181 -0
  28. package/dist/controllers/payment.controller.js +9 -0
  29. package/dist/controllers/podcast.controller.d.ts +575 -0
  30. package/dist/controllers/podcast.controller.js +9 -0
  31. package/dist/controllers/router-module.controller.d.ts +5 -0
  32. package/dist/controllers/router-module.controller.js +6 -0
  33. package/dist/controllers/studyguide.controller.d.ts +73 -0
  34. package/dist/controllers/studyguide.controller.js +9 -0
  35. package/dist/controllers/worksheets.controller.d.ts +829 -0
  36. package/dist/controllers/worksheets.controller.js +9 -0
  37. package/dist/controllers/workspace.controller.d.ts +1207 -0
  38. package/dist/controllers/workspace.controller.js +9 -0
  39. package/dist/lib/activity_human_description.test.js +16 -15
  40. package/dist/lib/activity_log_service.test.js +28 -23
  41. package/dist/lib/ai/config.d.ts +20 -0
  42. package/dist/lib/ai/config.js +31 -0
  43. package/dist/lib/ai/embedding-client.d.ts +8 -0
  44. package/dist/lib/ai/embedding-client.js +30 -0
  45. package/dist/lib/ai/index.d.ts +47 -0
  46. package/dist/lib/ai/index.js +28 -0
  47. package/dist/lib/ai/inference-backend/client.d.ts +28 -0
  48. package/dist/lib/ai/inference-backend/client.js +301 -0
  49. package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
  50. package/dist/lib/ai/inference-backend/mocks.js +133 -0
  51. package/dist/lib/ai/inference-backend/types.d.ts +44 -0
  52. package/dist/lib/ai/inference-backend/types.js +1 -0
  53. package/dist/lib/ai/json-parse.d.ts +2 -0
  54. package/dist/lib/ai/json-parse.js +34 -0
  55. package/dist/lib/ai/llm-client.d.ts +6 -0
  56. package/dist/lib/ai/llm-client.js +19 -0
  57. package/dist/lib/ai/mock.d.ts +2 -0
  58. package/dist/lib/ai/mock.js +10 -0
  59. package/dist/lib/ai/types.d.ts +9 -0
  60. package/dist/lib/ai/types.js +1 -0
  61. package/dist/lib/chunking.d.ts +19 -0
  62. package/dist/lib/chunking.js +47 -0
  63. package/dist/lib/curated-kb-seed.d.ts +12 -0
  64. package/dist/lib/curated-kb-seed.js +155 -0
  65. package/dist/lib/email.js +67 -108
  66. package/dist/lib/embeddings.d.ts +2 -0
  67. package/dist/lib/embeddings.js +1 -0
  68. package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
  69. package/dist/lib/ensure-curated-kb-catalog.js +53 -0
  70. package/dist/lib/env.d.ts +1 -5
  71. package/dist/lib/env.js +2 -7
  72. package/dist/lib/inference.d.ts +1 -8
  73. package/dist/lib/inference.js +1 -19
  74. package/dist/lib/kb-meta.d.ts +8 -0
  75. package/dist/lib/kb-meta.js +77 -0
  76. package/dist/lib/note-text.d.ts +1 -0
  77. package/dist/lib/note-text.js +47 -0
  78. package/dist/lib/notification-service.test.js +37 -36
  79. package/dist/lib/pdf.d.ts +11 -0
  80. package/dist/lib/pdf.js +11 -0
  81. package/dist/lib/usage_service.d.ts +2 -1
  82. package/dist/lib/usage_service.js +30 -12
  83. package/dist/lib/worksheet-generation.js +4 -4
  84. package/dist/lib/worksheet-generation.test.js +32 -17
  85. package/dist/lib/workspace-kb.d.ts +5 -0
  86. package/dist/lib/workspace-kb.js +7 -0
  87. package/dist/models/controller-context.model.d.ts +8 -0
  88. package/dist/models/controller-context.model.js +1 -0
  89. package/dist/repositories/artifact.repository.d.ts +60 -0
  90. package/dist/repositories/artifact.repository.js +40 -0
  91. package/dist/repositories/base.repository.d.ts +14 -0
  92. package/dist/repositories/base.repository.js +14 -0
  93. package/dist/repositories/invitation.repository.d.ts +94 -0
  94. package/dist/repositories/invitation.repository.js +44 -0
  95. package/dist/repositories/notification.repository.d.ts +72 -0
  96. package/dist/repositories/notification.repository.js +44 -0
  97. package/dist/repositories/router-module.repository.d.ts +10 -0
  98. package/dist/repositories/router-module.repository.js +14 -0
  99. package/dist/repositories/user.repository.d.ts +74 -0
  100. package/dist/repositories/user.repository.js +37 -0
  101. package/dist/repositories/workspace-member.repository.d.ts +31 -0
  102. package/dist/repositories/workspace-member.repository.js +31 -0
  103. package/dist/repositories/workspace.repository.d.ts +97 -0
  104. package/dist/repositories/workspace.repository.js +79 -0
  105. package/dist/routers/_app.d.ts +528 -33
  106. package/dist/routers/_app.js +4 -0
  107. package/dist/routers/admin.d.ts +0 -4
  108. package/dist/routers/admin.js +21 -549
  109. package/dist/routers/annotations.js +12 -170
  110. package/dist/routers/artifactVersions.d.ts +65 -0
  111. package/dist/routers/artifactVersions.js +14 -0
  112. package/dist/routers/auth.d.ts +0 -6
  113. package/dist/routers/auth.js +36 -421
  114. package/dist/routers/chat.js +15 -229
  115. package/dist/routers/copilot.d.ts +14 -13
  116. package/dist/routers/copilot.js +13 -532
  117. package/dist/routers/flashcards.d.ts +5 -5
  118. package/dist/routers/flashcards.js +23 -349
  119. package/dist/routers/knowledgeBase.d.ts +421 -0
  120. package/dist/routers/knowledgeBase.js +118 -0
  121. package/dist/routers/members.d.ts +0 -41
  122. package/dist/routers/members.js +22 -710
  123. package/dist/routers/notes.d.ts +94 -0
  124. package/dist/routers/notes.js +37 -0
  125. package/dist/routers/notifications.js +7 -109
  126. package/dist/routers/payment.d.ts +3 -2
  127. package/dist/routers/payment.js +11 -393
  128. package/dist/routers/podcast.d.ts +1 -1
  129. package/dist/routers/podcast.js +11 -784
  130. package/dist/routers/studyguide.js +3 -129
  131. package/dist/routers/worksheets.d.ts +29 -14
  132. package/dist/routers/worksheets.js +49 -628
  133. package/dist/routers/workspace.d.ts +0 -4
  134. package/dist/routers/workspace.js +28 -922
  135. package/dist/scripts/purge-deleted-users.js +2 -2
  136. package/dist/server.js +10 -3
  137. package/dist/services/activity/activity-human-description.service.d.ts +13 -0
  138. package/dist/services/activity/activity-human-description.service.js +221 -0
  139. package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
  140. package/dist/services/activity/activity-human-description.service.test.js +16 -0
  141. package/dist/services/activity/activity-log.service.d.ts +87 -0
  142. package/dist/services/activity/activity-log.service.js +276 -0
  143. package/dist/services/activity/activity-log.service.test.d.ts +1 -0
  144. package/dist/services/activity/activity-log.service.test.js +27 -0
  145. package/dist/services/activity-human-description.service.d.ts +13 -0
  146. package/dist/services/activity-human-description.service.js +221 -0
  147. package/dist/services/activity-human-description.service.test.d.ts +1 -0
  148. package/dist/services/activity-human-description.service.test.js +16 -0
  149. package/dist/services/activity-log.service.d.ts +87 -0
  150. package/dist/services/activity-log.service.js +276 -0
  151. package/dist/services/activity-log.service.test.d.ts +1 -0
  152. package/dist/services/activity-log.service.test.js +27 -0
  153. package/dist/services/admin/admin.service.d.ts +270 -0
  154. package/dist/services/admin/admin.service.js +476 -0
  155. package/dist/services/admin.service.d.ts +270 -0
  156. package/dist/services/admin.service.js +476 -0
  157. package/dist/services/ai/ai-session.service.d.ts +5 -0
  158. package/dist/services/ai/ai-session.service.js +4 -0
  159. package/dist/services/ai-session.service.d.ts +60 -0
  160. package/dist/services/ai-session.service.js +561 -0
  161. package/dist/services/annotation.service.d.ts +177 -0
  162. package/dist/services/annotation.service.js +154 -0
  163. package/dist/services/artifact-notification.service.d.ts +14 -0
  164. package/dist/services/artifact-notification.service.js +20 -0
  165. package/dist/services/artifact-version.service.d.ts +38 -0
  166. package/dist/services/artifact-version.service.js +129 -0
  167. package/dist/services/artifacts/annotation.service.d.ts +177 -0
  168. package/dist/services/artifacts/annotation.service.js +154 -0
  169. package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
  170. package/dist/services/artifacts/artifact-version.service.js +129 -0
  171. package/dist/services/artifacts/chat.service.d.ts +127 -0
  172. package/dist/services/artifacts/chat.service.js +182 -0
  173. package/dist/services/artifacts/study-guide.service.d.ts +18 -0
  174. package/dist/services/artifacts/study-guide.service.js +65 -0
  175. package/dist/services/auth/auth.service.d.ts +94 -0
  176. package/dist/services/auth/auth.service.js +368 -0
  177. package/dist/services/auth.service.d.ts +94 -0
  178. package/dist/services/auth.service.js +368 -0
  179. package/dist/services/base.service.d.ts +14 -0
  180. package/dist/services/base.service.js +14 -0
  181. package/dist/services/billing/payment.service.d.ts +55 -0
  182. package/dist/services/billing/payment.service.js +368 -0
  183. package/dist/services/billing/subscription.service.d.ts +37 -0
  184. package/dist/services/billing/subscription.service.js +654 -0
  185. package/dist/services/billing/usage.service.d.ts +27 -0
  186. package/dist/services/billing/usage.service.js +77 -0
  187. package/dist/services/chat.service.d.ts +127 -0
  188. package/dist/services/chat.service.js +182 -0
  189. package/dist/services/content/copilot.service.d.ts +113 -0
  190. package/dist/services/content/copilot.service.js +453 -0
  191. package/dist/services/content/flashcard-progress.service.d.ts +159 -0
  192. package/dist/services/content/flashcard-progress.service.js +432 -0
  193. package/dist/services/content/flashcard.service.d.ts +140 -0
  194. package/dist/services/content/flashcard.service.js +326 -0
  195. package/dist/services/content/media-analysis.service.d.ts +23 -0
  196. package/dist/services/content/media-analysis.service.js +404 -0
  197. package/dist/services/content/podcast.service.d.ts +267 -0
  198. package/dist/services/content/podcast.service.js +653 -0
  199. package/dist/services/content/worksheet-content.service.d.ts +37 -0
  200. package/dist/services/content/worksheet-content.service.js +84 -0
  201. package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
  202. package/dist/services/content/worksheet-content.service.test.js +69 -0
  203. package/dist/services/content/worksheet-generation.service.d.ts +91 -0
  204. package/dist/services/content/worksheet-generation.service.js +95 -0
  205. package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
  206. package/dist/services/content/worksheet-generation.service.test.js +20 -0
  207. package/dist/services/content/worksheet.service.d.ts +347 -0
  208. package/dist/services/content/worksheet.service.js +599 -0
  209. package/dist/services/copilot.service.d.ts +116 -0
  210. package/dist/services/copilot.service.js +447 -0
  211. package/dist/services/flashcard-progress.service.d.ts +2 -2
  212. package/dist/services/flashcard-progress.service.js +3 -2
  213. package/dist/services/flashcard.service.d.ts +140 -0
  214. package/dist/services/flashcard.service.js +325 -0
  215. package/dist/services/invitation.service.d.ts +66 -0
  216. package/dist/services/invitation.service.js +348 -0
  217. package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
  218. package/dist/services/knowledge/knowledge-base.service.js +544 -0
  219. package/dist/services/knowledge-base.service.d.ts +316 -0
  220. package/dist/services/knowledge-base.service.js +536 -0
  221. package/dist/services/media-analysis.service.d.ts +23 -0
  222. package/dist/services/media-analysis.service.js +384 -0
  223. package/dist/services/member.service.d.ts +36 -0
  224. package/dist/services/member.service.js +193 -0
  225. package/dist/services/members/invitation.service.d.ts +66 -0
  226. package/dist/services/members/invitation.service.js +348 -0
  227. package/dist/services/members/member.service.d.ts +36 -0
  228. package/dist/services/members/member.service.js +193 -0
  229. package/dist/services/note.service.d.ts +55 -0
  230. package/dist/services/note.service.js +111 -0
  231. package/dist/services/notification.service.d.ts +214 -0
  232. package/dist/services/notification.service.js +550 -0
  233. package/dist/services/notification.service.test.d.ts +1 -0
  234. package/dist/services/notification.service.test.js +87 -0
  235. package/dist/services/notifications/notification.service.d.ts +214 -0
  236. package/dist/services/notifications/notification.service.js +550 -0
  237. package/dist/services/notifications/notification.service.test.d.ts +1 -0
  238. package/dist/services/notifications/notification.service.test.js +87 -0
  239. package/dist/services/payment.service.d.ts +55 -0
  240. package/dist/services/payment.service.js +368 -0
  241. package/dist/services/podcast.service.d.ts +267 -0
  242. package/dist/services/podcast.service.js +654 -0
  243. package/dist/services/router-module.service.d.ts +7 -0
  244. package/dist/services/router-module.service.js +10 -0
  245. package/dist/services/study-guide.service.d.ts +18 -0
  246. package/dist/services/study-guide.service.js +65 -0
  247. package/dist/services/subscription.service.d.ts +37 -0
  248. package/dist/services/subscription.service.js +654 -0
  249. package/dist/services/usage-limit-policy.service.d.ts +12 -0
  250. package/dist/services/usage-limit-policy.service.js +22 -0
  251. package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
  252. package/dist/services/usage-limit-policy.service.test.js +46 -0
  253. package/dist/services/usage.service.d.ts +27 -0
  254. package/dist/services/usage.service.js +77 -0
  255. package/dist/services/worksheet-content.service.d.ts +42 -0
  256. package/dist/services/worksheet-content.service.js +84 -0
  257. package/dist/services/worksheet-content.service.test.d.ts +1 -0
  258. package/dist/services/worksheet-content.service.test.js +69 -0
  259. package/dist/services/worksheet-generation.service.d.ts +91 -0
  260. package/dist/services/worksheet-generation.service.js +95 -0
  261. package/dist/services/worksheet-generation.service.test.d.ts +1 -0
  262. package/dist/services/worksheet-generation.service.test.js +20 -0
  263. package/dist/services/worksheet.service.d.ts +385 -0
  264. package/dist/services/worksheet.service.js +596 -0
  265. package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
  266. package/dist/services/workspace/workspace-analytics.service.js +95 -0
  267. package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
  268. package/dist/services/workspace/workspace-kb.service.js +184 -0
  269. package/dist/services/workspace/workspace.service.d.ts +307 -0
  270. package/dist/services/workspace/workspace.service.js +394 -0
  271. package/dist/services/workspace-analytics.service.d.ts +24 -0
  272. package/dist/services/workspace-analytics.service.js +95 -0
  273. package/dist/services/workspace-kb.service.d.ts +40 -0
  274. package/dist/services/workspace-kb.service.js +184 -0
  275. package/dist/services/workspace-progress.service.d.ts +27 -0
  276. package/dist/services/workspace-progress.service.js +56 -0
  277. package/dist/services/workspace-progress.service.test.d.ts +1 -0
  278. package/dist/services/workspace-progress.service.test.js +49 -0
  279. package/dist/services/workspace.service.d.ts +307 -0
  280. package/dist/services/workspace.service.js +390 -0
  281. package/dist/trpc.js +2 -2
  282. package/package.json +5 -6
  283. package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
  284. package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
  285. package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
  286. package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
  287. package/prisma/schema.prisma +150 -48
  288. package/prisma/seed.mjs +67 -0
  289. package/scripts/debug/README.md +4 -0
  290. package/src/README.md +63 -0
  291. package/src/lib/ai/config.ts +34 -0
  292. package/src/lib/ai/embedding-client.ts +47 -0
  293. package/src/lib/ai/index.ts +62 -0
  294. package/src/lib/ai/inference-backend/client.ts +479 -0
  295. package/src/lib/ai/inference-backend/mocks.ts +171 -0
  296. package/src/lib/ai/inference-backend/types.ts +50 -0
  297. package/src/lib/ai/json-parse.ts +35 -0
  298. package/src/lib/ai/llm-client.ts +31 -0
  299. package/src/lib/ai/mock.ts +12 -0
  300. package/src/lib/ai/types.ts +11 -0
  301. package/src/lib/chunking.ts +81 -0
  302. package/src/lib/curated-kb-seed.ts +164 -0
  303. package/src/lib/email.ts +77 -115
  304. package/src/lib/embeddings.ts +9 -0
  305. package/src/lib/ensure-curated-kb-catalog.ts +60 -0
  306. package/src/lib/env.ts +2 -7
  307. package/src/lib/inference.ts +1 -21
  308. package/src/lib/kb-meta.ts +81 -0
  309. package/src/lib/pdf.ts +23 -0
  310. package/src/lib/workspace-kb.ts +7 -0
  311. package/src/repositories/artifact.repository.ts +55 -0
  312. package/src/repositories/base.repository.ts +19 -0
  313. package/src/repositories/invitation.repository.ts +53 -0
  314. package/src/repositories/notification.repository.ts +53 -0
  315. package/src/repositories/user.repository.ts +44 -0
  316. package/src/repositories/workspace-member.repository.ts +38 -0
  317. package/src/repositories/workspace.repository.ts +89 -0
  318. package/src/routers/_app.ts +4 -0
  319. package/src/routers/admin.ts +124 -692
  320. package/src/routers/annotations.ts +25 -203
  321. package/src/routers/artifactVersions.ts +32 -0
  322. package/src/routers/auth.ts +81 -519
  323. package/src/routers/chat.ts +42 -245
  324. package/src/routers/copilot.ts +41 -666
  325. package/src/routers/flashcards.ts +108 -404
  326. package/src/routers/knowledgeBase.ts +216 -0
  327. package/src/routers/members.ts +60 -782
  328. package/src/routers/notifications.ts +15 -117
  329. package/src/routers/payment.ts +37 -446
  330. package/src/routers/podcast.ts +36 -898
  331. package/src/routers/studyguide.ts +5 -144
  332. package/src/routers/worksheets.ts +171 -735
  333. package/src/routers/workspace.ts +138 -1109
  334. package/src/scripts/purge-deleted-users.ts +2 -2
  335. package/src/server.ts +10 -3
  336. package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
  337. package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
  338. package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
  339. package/src/services/admin/admin.service.ts +612 -0
  340. package/src/services/ai/ai-session.service.ts +5 -0
  341. package/src/services/artifacts/annotation.service.ts +189 -0
  342. package/src/services/artifacts/artifact-version.service.ts +151 -0
  343. package/src/services/artifacts/chat.service.ts +197 -0
  344. package/src/services/artifacts/study-guide.service.ts +72 -0
  345. package/src/services/auth/auth.service.ts +473 -0
  346. package/src/services/base.service.ts +19 -0
  347. package/src/services/billing/payment.service.ts +436 -0
  348. package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
  349. package/src/{lib/usage_service.ts → services/billing/usage.service.ts} +32 -12
  350. package/src/services/content/copilot.service.ts +596 -0
  351. package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +6 -3
  352. package/src/services/content/flashcard.service.ts +394 -0
  353. package/src/services/content/media-analysis.service.ts +556 -0
  354. package/src/services/content/podcast.service.ts +777 -0
  355. package/src/services/content/worksheet-content.service.test.ts +83 -0
  356. package/src/services/content/worksheet-content.service.ts +117 -0
  357. package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +1 -1
  358. package/src/services/content/worksheet.service.ts +751 -0
  359. package/src/services/knowledge/knowledge-base.service.ts +705 -0
  360. package/src/services/members/invitation.service.ts +427 -0
  361. package/src/services/members/member.service.ts +241 -0
  362. package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
  363. package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
  364. package/src/services/workspace/workspace-analytics.service.ts +107 -0
  365. package/src/services/workspace/workspace-kb.service.ts +273 -0
  366. package/src/services/workspace/workspace.service.ts +481 -0
  367. package/src/trpc.ts +2 -2
  368. package/src/lib/ai-session.ts +0 -704
  369. package/src/lib/workspace-access.ts +0 -13
  370. /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
  371. /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
  372. /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
  373. /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
  374. /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
  375. /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
  376. /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
  377. /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
  378. /package/src/{lib/worksheet-generation.ts → services/content/worksheet-generation.service.ts} +0 -0
@@ -65,6 +65,19 @@ enum ActivityLogStatus {
65
65
  FAILURE
66
66
  }
67
67
 
68
+ enum KnowledgeBaseStatus {
69
+ READY
70
+ INDEXING
71
+ ERROR
72
+ }
73
+
74
+ enum KnowledgeBaseDocumentStatus {
75
+ PENDING
76
+ PROCESSING
77
+ READY
78
+ FAILED
79
+ }
80
+
68
81
  //
69
82
  // NextAuth-compatible auth models (minimal)
70
83
  //
@@ -106,6 +119,8 @@ model User {
106
119
  idempotencyRecords IdempotencyRecord[]
107
120
  activityLogs ActivityLog[] @relation("ActivityLogActor")
108
121
  passwordResetTokens PasswordResetToken[]
122
+ knowledgeBases KnowledgeBase[] @relation("UserKnowledgeBases")
123
+ workspaceKnowledgeBases WorkspaceKnowledgeBase[] @relation("UserWorkspaceKnowledgeBases")
109
124
  }
110
125
 
111
126
  /// One-time tokens for forgot-password flow (token stored as SHA-256 hash of the secret from the email link).
@@ -128,7 +143,7 @@ model Role {
128
143
  }
129
144
 
130
145
  model Notification {
131
- id String @id @default(cuid())
146
+ id String @id @default(cuid())
132
147
  userId String
133
148
  actorUserId String?
134
149
  workspaceId String?
@@ -138,22 +153,22 @@ model Notification {
138
153
  content String?
139
154
  actionUrl String?
140
155
  metadata Json?
141
- priority NotificationPriority @default(NORMAL)
156
+ priority NotificationPriority @default(NORMAL)
142
157
  sourceId String?
143
- read Boolean @default(false)
158
+ read Boolean @default(false)
144
159
  readAt DateTime?
145
160
  deliveredAt DateTime?
146
- createdAt DateTime @default(now())
147
- updatedAt DateTime @updatedAt
148
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
149
- actor User? @relation("NotificationActor", fields: [actorUserId], references: [id], onDelete: SetNull)
150
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
161
+ createdAt DateTime @default(now())
162
+ updatedAt DateTime @updatedAt
163
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
164
+ actor User? @relation("NotificationActor", fields: [actorUserId], references: [id], onDelete: SetNull)
165
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
151
166
 
167
+ @@unique([userId, type, sourceId])
152
168
  @@index([userId, read, createdAt(sort: Desc)])
153
169
  @@index([userId, createdAt(sort: Desc)])
154
170
  @@index([type, createdAt(sort: Desc)])
155
171
  @@index([workspaceId])
156
- @@unique([userId, type, sourceId])
157
172
  }
158
173
 
159
174
  model Session {
@@ -212,6 +227,7 @@ model Workspace {
212
227
  invitations WorkspaceInvitation[]
213
228
  notifications Notification[]
214
229
  activityLogs ActivityLog[]
230
+ knowledgeBases WorkspaceKnowledgeBase[]
215
231
  createdAt DateTime @default(now())
216
232
  updatedAt DateTime @updatedAt
217
233
 
@@ -243,15 +259,15 @@ model Chat {
243
259
  }
244
260
 
245
261
  model CopilotConversation {
246
- id String @id @default(cuid())
262
+ id String @id @default(cuid())
247
263
  workspaceId String
248
- workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
264
+ workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
249
265
  userId String
250
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
251
- title String @default("New Chat")
266
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
267
+ title String @default("New Chat")
252
268
  messages CopilotMessage[]
253
- createdAt DateTime @default(now())
254
- updatedAt DateTime @updatedAt
269
+ createdAt DateTime @default(now())
270
+ updatedAt DateTime @updatedAt
255
271
 
256
272
  @@index([workspaceId, userId, updatedAt])
257
273
  }
@@ -440,15 +456,15 @@ model WorksheetQuestionProgress {
440
456
  }
441
457
 
442
458
  model WorksheetPreset {
443
- id String @id @default(cuid())
459
+ id String @id @default(cuid())
444
460
  userId String?
445
461
  workspaceId String?
446
462
  name String
447
- isSystem Boolean @default(false)
463
+ isSystem Boolean @default(false)
448
464
  config Json
449
- createdAt DateTime @default(now())
450
- updatedAt DateTime @updatedAt
451
- user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
465
+ createdAt DateTime @default(now())
466
+ updatedAt DateTime @updatedAt
467
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
452
468
  workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
453
469
 
454
470
  @@index([userId, workspaceId])
@@ -512,18 +528,18 @@ model PodcastSegment {
512
528
  }
513
529
 
514
530
  model Invoice {
515
- id String @id @default(cuid())
531
+ id String @id @default(cuid())
516
532
  userId String
517
533
  subscriptionId String?
518
- stripeInvoiceId String @unique
534
+ stripeInvoiceId String @unique
519
535
  amountPaid Int
520
536
  status String
521
537
  invoicePdfUrl String?
522
538
  hostedInvoiceUrl String?
523
539
  paidAt DateTime?
524
- type InvoiceType @default(SUBSCRIPTION)
525
- createdAt DateTime @default(now())
526
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
540
+ type InvoiceType @default(SUBSCRIPTION)
541
+ createdAt DateTime @default(now())
542
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
527
543
  subscription Subscription? @relation(fields: [subscriptionId], references: [id])
528
544
 
529
545
  @@index([userId])
@@ -596,48 +612,48 @@ model UserCredit {
596
612
  }
597
613
 
598
614
  model IdempotencyRecord {
599
- id String @id @default(cuid())
600
- userId String
601
- planId String? // The plan being purchased
602
- resourceType ArtifactType? // The resource for top-ups
603
- stripeSessionId String? // The Stripe Checkout Session ID
604
- status String @default("pending") // pending, completed, failed, expired
605
- activeLockKey String? @unique // Unique lock: "user_id_plan_id" (Nullified when done)
606
-
607
- createdAt DateTime @default(now())
608
- updatedAt DateTime @updatedAt
609
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
615
+ id String @id @default(cuid())
616
+ userId String
617
+ planId String? // The plan being purchased
618
+ resourceType ArtifactType? // The resource for top-ups
619
+ stripeSessionId String? // The Stripe Checkout Session ID
620
+ status String @default("pending") // pending, completed, failed, expired
621
+ activeLockKey String? @unique // Unique lock: "user_id_plan_id" (Nullified when done)
622
+
623
+ createdAt DateTime @default(now())
624
+ updatedAt DateTime @updatedAt
625
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
610
626
 
611
627
  @@index([userId, status])
612
628
  @@index([activeLockKey])
613
629
  }
614
630
 
615
631
  model StripeEvent {
616
- id String @id @default(cuid())
617
- stripeEventId String @unique // Stripe event ID (e.g. evt_...)
618
- type String // Event type (e.g. checkout.session.completed)
619
- status String @default("pending") // pending, processed, failed
620
- error String? // Error message if processing fails
621
- processedAt DateTime?
622
- createdAt DateTime @default(now())
623
- updatedAt DateTime @updatedAt
632
+ id String @id @default(cuid())
633
+ stripeEventId String @unique // Stripe event ID (e.g. evt_...)
634
+ type String // Event type (e.g. checkout.session.completed)
635
+ status String @default("pending") // pending, processed, failed
636
+ error String? // Error message if processing fails
637
+ processedAt DateTime?
638
+ createdAt DateTime @default(now())
639
+ updatedAt DateTime @updatedAt
624
640
 
625
641
  @@index([stripeEventId])
626
642
  }
627
643
 
628
644
  /// Append-only system / user activity (tRPC and explicit events). Retention via admin or scheduled job.
629
645
  model ActivityLog {
630
- id String @id @default(cuid())
631
- createdAt DateTime @default(now())
646
+ id String @id @default(cuid())
647
+ createdAt DateTime @default(now())
632
648
  actorUserId String?
633
- actor User? @relation("ActivityLogActor", fields: [actorUserId], references: [id], onDelete: SetNull)
649
+ actor User? @relation("ActivityLogActor", fields: [actorUserId], references: [id], onDelete: SetNull)
634
650
  actorEmailSnapshot String?
635
651
  action String
636
652
  category ActivityLogCategory
637
653
  resourceType String?
638
654
  resourceId String?
639
655
  workspaceId String?
640
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
656
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
641
657
  trpcPath String?
642
658
  httpMethod String?
643
659
  status ActivityLogStatus
@@ -653,3 +669,89 @@ model ActivityLog {
653
669
  @@index([category, createdAt(sort: Desc)])
654
670
  }
655
671
 
672
+ /// A retrieval-augmented knowledge base. Knowledge bases live in a global
673
+ /// catalog managed by System Admins; workspaces opt-in by attaching one
674
+ /// (see `WorkspaceKnowledgeBase`). When `isCurated = true` the KB shows up
675
+ /// in the user-facing catalog search so any workspace can add it.
676
+ ///
677
+ /// Each knowledge base owns uploaded documents (PDFs, etc.) which are split
678
+ /// into chunks with pgvector embeddings for semantic search.
679
+ model KnowledgeBase {
680
+ id String @id @default(cuid())
681
+ createdById String?
682
+ createdBy User? @relation("UserKnowledgeBases", fields: [createdById], references: [id], onDelete: SetNull)
683
+ name String
684
+ description String?
685
+ isCurated Boolean @default(false)
686
+ status KnowledgeBaseStatus @default(READY)
687
+ embeddingModel String @default("text-embedding-3-small")
688
+ embeddingDim Int @default(1536)
689
+ meta Json?
690
+ documents KnowledgeBaseDocument[]
691
+ workspaces WorkspaceKnowledgeBase[]
692
+ createdAt DateTime @default(now())
693
+ updatedAt DateTime @updatedAt
694
+
695
+ @@index([isCurated, updatedAt(sort: Desc)])
696
+ }
697
+
698
+ /// Many-to-many join between Workspace and KnowledgeBase. A row exists
699
+ /// whenever a workspace has "added" a knowledge base from the catalog (or
700
+ /// when an admin attaches one directly).
701
+ model WorkspaceKnowledgeBase {
702
+ id String @id @default(cuid())
703
+ workspaceId String
704
+ workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
705
+ knowledgeBaseId String
706
+ knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
707
+ addedById String?
708
+ addedBy User? @relation("UserWorkspaceKnowledgeBases", fields: [addedById], references: [id], onDelete: SetNull)
709
+ createdAt DateTime @default(now())
710
+
711
+ @@unique([workspaceId, knowledgeBaseId])
712
+ @@index([workspaceId])
713
+ @@index([knowledgeBaseId])
714
+ }
715
+
716
+ /// A single uploaded source document inside a knowledge base.
717
+ model KnowledgeBaseDocument {
718
+ id String @id @default(cuid())
719
+ knowledgeBaseId String
720
+ knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
721
+ name String
722
+ mimeType String
723
+ size Int
724
+ bucket String?
725
+ objectKey String?
726
+ status KnowledgeBaseDocumentStatus @default(PENDING)
727
+ errorMessage String?
728
+ numChunks Int @default(0)
729
+ numPages Int?
730
+ meta Json?
731
+ chunks KnowledgeBaseChunk[]
732
+ createdAt DateTime @default(now())
733
+ updatedAt DateTime @updatedAt
734
+
735
+ @@index([knowledgeBaseId])
736
+ @@index([knowledgeBaseId, createdAt(sort: Desc)])
737
+ }
738
+
739
+ /// A single text chunk inside a document. The `embedding` column is a
740
+ /// pgvector value; Prisma cannot generate types for it, so similarity
741
+ /// search must be performed via raw SQL (`$queryRaw`). The dimension is
742
+ /// fixed at 1536 to match `text-embedding-3-small`.
743
+ model KnowledgeBaseChunk {
744
+ id String @id @default(cuid())
745
+ documentId String
746
+ document KnowledgeBaseDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
747
+ knowledgeBaseId String
748
+ chunkIndex Int
749
+ pageNumber Int?
750
+ content String
751
+ tokenCount Int?
752
+ embedding Unsupported("vector(1536)")?
753
+ createdAt DateTime @default(now())
754
+
755
+ @@index([knowledgeBaseId])
756
+ @@index([documentId, chunkIndex])
757
+ }
@@ -0,0 +1,67 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+
3
+ /** Keep in sync with server/src/lib/curated-kb-seed.ts */
4
+ const CURATED_KB_SEEDS = [
5
+ { slug: 'ap-biology', name: 'AP Biology', description: 'Cell biology, genetics, evolution, and ecology aligned with the AP Biology curriculum.', category: 'AP', subject: 'biology' },
6
+ { slug: 'ap-chemistry', name: 'AP Chemistry', description: 'Atomic structure, bonding, thermodynamics, and kinetics for AP Chemistry.', category: 'AP', subject: 'chemistry' },
7
+ { slug: 'ap-physics-1', name: 'AP Physics 1', description: 'Algebra-based mechanics, waves, and electricity for AP Physics 1.', category: 'AP', subject: 'physics' },
8
+ { slug: 'ap-calculus-ab', name: 'AP Calculus AB', description: 'Limits, derivatives, integrals, and the Fundamental Theorem of Calculus.', category: 'AP', subject: 'calculus' },
9
+ { slug: 'ap-calculus-bc', name: 'AP Calculus BC', description: 'Series, parametric equations, polar coordinates, and advanced integration.', category: 'AP', subject: 'calculus' },
10
+ { slug: 'ap-us-history', name: 'AP US History', description: 'Colonial America through the modern era with primary source analysis.', category: 'AP', subject: 'history' },
11
+ { slug: 'ap-world-history', name: 'AP World History', description: 'Global civilizations, trade networks, and historical thinking skills.', category: 'AP', subject: 'history' },
12
+ { slug: 'ap-english-lang', name: 'AP English Language', description: 'Rhetorical analysis, argumentation, and synthesis writing strategies.', category: 'AP', subject: 'english' },
13
+ { slug: 'ap-english-lit', name: 'AP English Literature', description: 'Literary analysis, poetry, prose fiction, and critical essay writing.', category: 'AP', subject: 'literature' },
14
+ { slug: 'ap-psychology', name: 'AP Psychology', description: 'Biological bases of behavior, cognition, development, and social psychology.', category: 'AP', subject: 'psychology' },
15
+ { slug: 'ap-environmental-science', name: 'AP Environmental Science', description: 'Ecosystems, biodiversity, pollution, and sustainability concepts.', category: 'AP', subject: 'environmental' },
16
+ { slug: 'ap-macroeconomics', name: 'AP Macroeconomics', description: 'GDP, inflation, fiscal and monetary policy, and international trade.', category: 'AP', subject: 'economics' },
17
+ { slug: 'ib-biology-hl', name: 'IB Biology HL', description: 'Higher Level biology: molecular biology, genetics, ecology, and human physiology.', category: 'IB', subject: 'biology' },
18
+ { slug: 'ib-chemistry-hl', name: 'IB Chemistry HL', description: 'Higher Level chemistry: organic, inorganic, physical, and analytical topics.', category: 'IB', subject: 'chemistry' },
19
+ { slug: 'ib-physics-hl', name: 'IB Physics HL', description: 'Higher Level physics: mechanics, fields, waves, and nuclear physics.', category: 'IB', subject: 'physics' },
20
+ { slug: 'ib-math-aa-hl', name: 'IB Math AA HL', description: 'Analysis & Approaches HL: calculus, proof, vectors, and complex numbers.', category: 'IB', subject: 'math' },
21
+ { slug: 'ib-math-ai-hl', name: 'IB Math AI HL', description: 'Applications & Interpretation HL: statistics, modelling, and technology use.', category: 'IB', subject: 'math' },
22
+ { slug: 'ib-history-hl', name: 'IB History HL', description: 'Higher Level history: 20th century world history and historical investigation.', category: 'IB', subject: 'history' },
23
+ { slug: 'ib-english-a-hl', name: 'IB English A HL', description: 'Language & Literature HL: textual analysis, comparative study, and IO prep.', category: 'IB', subject: 'literature' },
24
+ { slug: 'ib-economics-hl', name: 'IB Economics HL', description: 'Microeconomics, macroeconomics, international economics, and development.', category: 'IB', subject: 'economics' },
25
+ { slug: 'ib-psychology-hl', name: 'IB Psychology HL', description: 'Biological, cognitive, sociocultural, and abnormal psychology at HL depth.', category: 'IB', subject: 'psychology' },
26
+ ];
27
+
28
+ const prisma = new PrismaClient();
29
+
30
+ async function main() {
31
+ for (const seed of CURATED_KB_SEEDS) {
32
+ const existing = await prisma.knowledgeBase.findFirst({
33
+ where: { meta: { path: ['slug'], equals: seed.slug } },
34
+ });
35
+
36
+ if (existing) {
37
+ await prisma.knowledgeBase.update({
38
+ where: { id: existing.id },
39
+ data: {
40
+ name: seed.name,
41
+ description: seed.description,
42
+ isCurated: true,
43
+ meta: { slug: seed.slug, category: seed.category, subject: seed.subject },
44
+ },
45
+ });
46
+ continue;
47
+ }
48
+
49
+ await prisma.knowledgeBase.create({
50
+ data: {
51
+ name: seed.name,
52
+ description: seed.description,
53
+ isCurated: true,
54
+ meta: { slug: seed.slug, category: seed.category, subject: seed.subject },
55
+ },
56
+ });
57
+ }
58
+
59
+ console.log(`Seeded ${CURATED_KB_SEEDS.length} curated knowledge bases.`);
60
+ }
61
+
62
+ main()
63
+ .catch((e) => {
64
+ console.error(e);
65
+ process.exit(1);
66
+ })
67
+ .finally(() => prisma.$disconnect());
@@ -0,0 +1,4 @@
1
+ # Debug scripts
2
+
3
+ Ad-hoc scripts used once during development / debugging. Kept out of `src/`
4
+ so the build surface doesn't pick them up. Safe to delete if not needed.
package/src/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Server source layout
2
+
3
+ This server uses a layered architecture. Please keep new code in the right
4
+ layer so routers don't grow back to 1000+ lines again.
5
+
6
+ ## Layers
7
+
8
+ ```
9
+ tRPC Client -> routers/*.ts Zod input + middleware + glue
10
+ -> services/*.ts business logic and orchestration
11
+ -> repositories/*.ts Prisma queries
12
+ -> lib/* infra: email, pusher, stripe, storage,
13
+ inference, logger, errors, env, etc.
14
+ ```
15
+
16
+ - `routers/` — **thin**. Each procedure:
17
+ 1. Declares its Zod input schema.
18
+ 2. Selects a procedure type (`authedProcedure`, `verifiedProcedure`, etc.).
19
+ 3. Instantiates a service (`new FooService(ctx.db)`) and returns its result.
20
+ 4. Optionally handles transport-only concerns (e.g. cookies in
21
+ `auth.ts`).
22
+ 5. Does **not** call Prisma directly. Does **not** contain business
23
+ logic beyond trivial response shaping.
24
+ - `services/` — **business logic**. One service per domain aggregate.
25
+ Constructor signature is `(db: PrismaClient)` via `BaseService`. Services
26
+ can depend on other services and on repositories, but must **not**
27
+ depend on `Context`, `Request`, or other HTTP types.
28
+ - `repositories/` — **data access**. Thin Prisma wrappers per aggregate.
29
+ Expose intent-revealing methods (`findAccessibleById`, `listOwned`) so
30
+ the shape of `where` clauses doesn't leak into services.
31
+ - `lib/` — infrastructure and pure utilities: Prisma client singleton,
32
+ Stripe SDK, email transport, Pusher client, Supabase client, logger,
33
+ shared error classes, env validation, retry helper, validation helpers.
34
+ **Not** domain services.
35
+
36
+ ## Conventions
37
+
38
+ - **File naming**: `{kebab-case-domain}.service.ts`,
39
+ `{kebab-case-domain}.repository.ts` (singular).
40
+ - **Class naming**: `FooService`, `FooRepository`.
41
+ - **Constructor injection**: every service/repository takes a
42
+ `PrismaClient` in its constructor. Instantiate per-request from the
43
+ router (`new FooService(ctx.db)`).
44
+ - **Workspace access**: use `workspaceAccessWhere(userId)` from
45
+ `repositories/workspace.repository.ts` for member-inclusive access, or
46
+ `workspaceOwnerWhere(userId)` for owner-only. Don't hand-roll
47
+ `OR: [{ ownerId }, …]` again.
48
+ - **Errors**: throw `TRPCError` for HTTP-shaped errors in services. They
49
+ propagate cleanly back through the router.
50
+
51
+ ## Folders
52
+
53
+ - `context.ts` — tRPC context builder (session + db + req/res).
54
+ - `trpc.ts` — procedure types and middleware (auth, verification, plan
55
+ limits, activity logging).
56
+ - `routers/` — one file per top-level router, plus `_app.ts` composition.
57
+ - `services/` — domain services (router → service → repository).
58
+ - `repositories/` — Prisma access per aggregate.
59
+ - `lib/` — infrastructure and shared utilities.
60
+ - `types/` — shared TS types.
61
+ - `scripts/` — operational tooling (cron-style tasks).
62
+
63
+ See `REFACTOR_NOTES.md` at the repo root for known follow-up work.
@@ -0,0 +1,34 @@
1
+ export const aiConfig = {
2
+ llm: {
3
+ apiKey: process.env.INFERENCE_API_KEY,
4
+ baseUrl: process.env.INFERENCE_BASE_URL,
5
+ model: process.env.INFERENCE_MODEL ?? 'command-a-03-2025',
6
+ },
7
+ embeddings: {
8
+ apiKey:
9
+ process.env.OPENAI_API_KEY,
10
+ baseUrl:
11
+ undefined,
12
+ model: process.env.EMBEDDING_MODEL ?? 'text-embedding-3-small',
13
+ dim: Number(process.env.EMBEDDING_DIM ?? 1536),
14
+ },
15
+ inferenceBackend: {
16
+ url: process.env.INFERENCE_API_URL,
17
+ mockEnabled: process.env.DONT_TEST_INFERENCE === 'true',
18
+ mockDelayMs: process.env.DONT_TEST_INFERENCE === 'true' ? 10_000 : 0,
19
+ },
20
+ } as const;
21
+
22
+ export function getInferenceBackendUploadUrl(): string {
23
+ const base = aiConfig.inferenceBackend.url;
24
+ if (!base) {
25
+ throw new Error('INFERENCE_API_URL is not configured');
26
+ }
27
+ return `${base.replace(/\/$/, '')}/upload`;
28
+ }
29
+
30
+ export function tryGetInferenceBackendUploadUrl(): string | null {
31
+ const base = aiConfig.inferenceBackend.url;
32
+ if (!base) return null;
33
+ return `${base.replace(/\/$/, '')}/upload`;
34
+ }
@@ -0,0 +1,47 @@
1
+ import OpenAI from 'openai';
2
+ import { aiConfig } from './config.js';
3
+
4
+ const client = new OpenAI({
5
+ apiKey: aiConfig.embeddings.apiKey,
6
+ baseURL: aiConfig.embeddings.baseUrl,
7
+ });
8
+
9
+ export const DEFAULT_EMBEDDING_MODEL = aiConfig.embeddings.model;
10
+ export const DEFAULT_EMBEDDING_DIM = aiConfig.embeddings.dim;
11
+
12
+ export interface EmbedOptions {
13
+ model?: string;
14
+ }
15
+
16
+ export async function embedTexts(
17
+ texts: string[],
18
+ opts: EmbedOptions = {},
19
+ ): Promise<number[][]> {
20
+ const model = opts.model ?? DEFAULT_EMBEDDING_MODEL;
21
+
22
+ if (texts.length === 0) return [];
23
+
24
+ const BATCH = 96;
25
+ const out: number[][] = new Array(texts.length);
26
+ for (let i = 0; i < texts.length; i += BATCH) {
27
+ const batch = texts.slice(i, i + BATCH);
28
+
29
+ const res = await client.embeddings.create({ model, input: batch });
30
+ res.data.forEach((row, j) => {
31
+ out[i + j] = row.embedding as number[];
32
+ });
33
+ }
34
+ return out;
35
+ }
36
+
37
+ export async function embedQuery(
38
+ text: string,
39
+ opts: EmbedOptions = {},
40
+ ): Promise<number[]> {
41
+ const [vec] = await embedTexts([text], opts);
42
+ return vec;
43
+ }
44
+
45
+ export function toVectorLiteral(vec: number[]): string {
46
+ return `[${vec.map((n) => (Number.isFinite(n) ? n : 0)).join(',')}]`;
47
+ }
@@ -0,0 +1,62 @@
1
+ import { aiConfig } from './config.js';
2
+ import {
3
+ complete,
4
+ completeText,
5
+ } from './llm-client.js';
6
+ import {
7
+ DEFAULT_EMBEDDING_DIM,
8
+ DEFAULT_EMBEDDING_MODEL,
9
+ embedQuery,
10
+ embedTexts,
11
+ toVectorLiteral,
12
+ } from './embedding-client.js';
13
+ import { extractJson, parseJsonField } from './json-parse.js';
14
+ import { isAiMockMode, mockDelay } from './mock.js';
15
+ import { inferenceBackend } from './inference-backend/client.js';
16
+
17
+ export const ai = {
18
+ config: aiConfig,
19
+ isMockMode: isAiMockMode,
20
+ mockDelay,
21
+ llm: {
22
+ complete,
23
+ completeText,
24
+ },
25
+ embed: {
26
+ texts: embedTexts,
27
+ query: embedQuery,
28
+ toVectorLiteral,
29
+ DEFAULT_MODEL: DEFAULT_EMBEDDING_MODEL,
30
+ DEFAULT_DIM: DEFAULT_EMBEDDING_DIM,
31
+ },
32
+ backend: inferenceBackend,
33
+ parse: {
34
+ extractJson,
35
+ parseJsonField,
36
+ },
37
+ };
38
+
39
+ export type { ChatMessage, ChatRole, CompleteOptions } from './types.js';
40
+ export type {
41
+ AISession,
42
+ ProcessFileResult,
43
+ PodcastSpeaker,
44
+ StudyGuideSegment,
45
+ WorksheetGenerationOptions,
46
+ } from './inference-backend/types.js';
47
+
48
+ export {
49
+ aiConfig,
50
+ complete,
51
+ completeText,
52
+ DEFAULT_EMBEDDING_DIM,
53
+ DEFAULT_EMBEDDING_MODEL,
54
+ embedQuery,
55
+ embedTexts,
56
+ extractJson,
57
+ inferenceBackend,
58
+ isAiMockMode,
59
+ mockDelay,
60
+ parseJsonField,
61
+ toVectorLiteral,
62
+ };