@goscribe/server 1.0.8 → 1.0.9
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.
- package/AUTH_FRONTEND_SPEC.md +21 -0
- package/CHAT_FRONTEND_SPEC.md +474 -0
- package/MEETINGSUMMARY_FRONTEND_SPEC.md +28 -0
- package/PODCAST_FRONTEND_SPEC.md +595 -0
- package/STUDYGUIDE_FRONTEND_SPEC.md +18 -0
- package/WORKSHEETS_FRONTEND_SPEC.md +26 -0
- package/WORKSPACE_FRONTEND_SPEC.md +47 -0
- package/dist/lib/ai-session.d.ts +26 -0
- package/dist/lib/ai-session.js +343 -0
- package/dist/lib/inference.d.ts +2 -0
- package/dist/lib/inference.js +21 -0
- package/dist/lib/pusher.d.ts +14 -0
- package/dist/lib/pusher.js +94 -0
- package/dist/lib/storage.d.ts +10 -2
- package/dist/lib/storage.js +63 -6
- package/dist/routers/_app.d.ts +840 -58
- package/dist/routers/_app.js +6 -0
- package/dist/routers/ai-session.d.ts +0 -0
- package/dist/routers/ai-session.js +1 -0
- package/dist/routers/auth.d.ts +1 -0
- package/dist/routers/auth.js +6 -4
- package/dist/routers/chat.d.ts +171 -0
- package/dist/routers/chat.js +270 -0
- package/dist/routers/flashcards.d.ts +37 -0
- package/dist/routers/flashcards.js +128 -0
- package/dist/routers/meetingsummary.d.ts +0 -0
- package/dist/routers/meetingsummary.js +377 -0
- package/dist/routers/podcast.d.ts +277 -0
- package/dist/routers/podcast.js +847 -0
- package/dist/routers/studyguide.d.ts +54 -0
- package/dist/routers/studyguide.js +125 -0
- package/dist/routers/worksheets.d.ts +138 -51
- package/dist/routers/worksheets.js +317 -7
- package/dist/routers/workspace.d.ts +162 -7
- package/dist/routers/workspace.js +440 -8
- package/dist/server.js +6 -2
- package/package.json +11 -4
- package/prisma/migrations/20250826124819_add_worksheet_difficulty_and_estimated_time/migration.sql +213 -0
- package/prisma/migrations/20250826133236_add_worksheet_question_progress/migration.sql +31 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +87 -6
- package/prisma/seed.mjs +135 -0
- package/src/lib/ai-session.ts +411 -0
- package/src/lib/inference.ts +21 -0
- package/src/lib/pusher.ts +104 -0
- package/src/lib/storage.ts +89 -6
- package/src/routers/_app.ts +6 -0
- package/src/routers/auth.ts +8 -4
- package/src/routers/chat.ts +275 -0
- package/src/routers/flashcards.ts +142 -0
- package/src/routers/meetingsummary.ts +416 -0
- package/src/routers/podcast.ts +934 -0
- package/src/routers/studyguide.ts +144 -0
- package/src/routers/worksheets.ts +336 -7
- package/src/routers/workspace.ts +487 -8
- package/src/server.ts +7 -2
- package/test-ai-integration.js +134 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { TRPCError } from '@trpc/server';
|
|
3
3
|
import { router, authedProcedure } from '../trpc.js';
|
|
4
|
+
import { aiSessionService } from '../lib/ai-session.js';
|
|
5
|
+
import PusherService from '../lib/pusher.js';
|
|
4
6
|
// Avoid importing Prisma enums directly; mirror values as string literals
|
|
5
7
|
const ArtifactType = {
|
|
6
8
|
WORKSHEET: 'WORKSHEET',
|
|
@@ -10,6 +12,14 @@ const Difficulty = {
|
|
|
10
12
|
MEDIUM: 'MEDIUM',
|
|
11
13
|
HARD: 'HARD',
|
|
12
14
|
};
|
|
15
|
+
const QuestionType = {
|
|
16
|
+
MULTIPLE_CHOICE: 'MULTIPLE_CHOICE',
|
|
17
|
+
TEXT: 'TEXT',
|
|
18
|
+
NUMERIC: 'NUMERIC',
|
|
19
|
+
TRUE_FALSE: 'TRUE_FALSE',
|
|
20
|
+
MATCHING: 'MATCHING',
|
|
21
|
+
FILL_IN_THE_BLANK: 'FILL_IN_THE_BLANK',
|
|
22
|
+
};
|
|
13
23
|
export const worksheets = router({
|
|
14
24
|
// List all worksheet artifacts for a workspace
|
|
15
25
|
list: authedProcedure
|
|
@@ -28,23 +38,76 @@ export const worksheets = router({
|
|
|
28
38
|
});
|
|
29
39
|
if (!worksheets)
|
|
30
40
|
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
31
|
-
|
|
41
|
+
// Merge per-user progress into question.meta for compatibility with UI
|
|
42
|
+
const allQuestionIds = worksheets.flatMap(w => w.questions.map(q => q.id));
|
|
43
|
+
if (allQuestionIds.length === 0)
|
|
44
|
+
return worksheets;
|
|
45
|
+
const progress = await ctx.db.worksheetQuestionProgress.findMany({
|
|
46
|
+
where: { userId: ctx.session.user.id, worksheetQuestionId: { in: allQuestionIds } },
|
|
47
|
+
});
|
|
48
|
+
const progressByQuestionId = new Map(progress.map(p => [p.worksheetQuestionId, p]));
|
|
49
|
+
const merged = worksheets.map(w => ({
|
|
50
|
+
...w,
|
|
51
|
+
questions: w.questions.map(q => {
|
|
52
|
+
const p = progressByQuestionId.get(q.id);
|
|
53
|
+
if (!p)
|
|
54
|
+
return q;
|
|
55
|
+
const existingMeta = q.meta ? (typeof q.meta === 'object' ? q.meta : JSON.parse(q.meta)) : {};
|
|
56
|
+
return {
|
|
57
|
+
...q,
|
|
58
|
+
meta: {
|
|
59
|
+
...existingMeta,
|
|
60
|
+
completed: p.completed,
|
|
61
|
+
userAnswer: p.userAnswer,
|
|
62
|
+
completedAt: p.completedAt,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}),
|
|
66
|
+
}));
|
|
67
|
+
return merged;
|
|
32
68
|
}),
|
|
33
69
|
// Create a worksheet set
|
|
34
|
-
|
|
35
|
-
.input(z.object({
|
|
70
|
+
create: authedProcedure
|
|
71
|
+
.input(z.object({
|
|
72
|
+
workspaceId: z.string(),
|
|
73
|
+
title: z.string().min(1).max(120),
|
|
74
|
+
description: z.string().optional(),
|
|
75
|
+
difficulty: z.enum(['EASY', 'MEDIUM', 'HARD']).optional(),
|
|
76
|
+
estimatedTime: z.string().optional(),
|
|
77
|
+
problems: z.array(z.object({
|
|
78
|
+
question: z.string().min(1),
|
|
79
|
+
answer: z.string().min(1),
|
|
80
|
+
type: z.enum(['MULTIPLE_CHOICE', 'TEXT', 'NUMERIC', 'TRUE_FALSE', 'MATCHING', 'FILL_IN_THE_BLANK']).default('TEXT'),
|
|
81
|
+
options: z.array(z.string()).optional(),
|
|
82
|
+
})).optional(),
|
|
83
|
+
}))
|
|
36
84
|
.mutation(async ({ ctx, input }) => {
|
|
37
85
|
const workspace = await ctx.db.workspace.findFirst({
|
|
38
86
|
where: { id: input.workspaceId, ownerId: ctx.session.user.id },
|
|
39
87
|
});
|
|
40
88
|
if (!workspace)
|
|
41
89
|
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
90
|
+
const { problems, ...worksheetData } = input;
|
|
42
91
|
return ctx.db.artifact.create({
|
|
43
92
|
data: {
|
|
44
93
|
workspaceId: input.workspaceId,
|
|
45
94
|
type: ArtifactType.WORKSHEET,
|
|
46
95
|
title: input.title,
|
|
96
|
+
difficulty: input.difficulty,
|
|
97
|
+
estimatedTime: input.estimatedTime,
|
|
47
98
|
createdById: ctx.session.user.id,
|
|
99
|
+
questions: problems ? {
|
|
100
|
+
create: problems.map((problem, index) => ({
|
|
101
|
+
prompt: problem.question,
|
|
102
|
+
answer: problem.answer,
|
|
103
|
+
type: problem.type,
|
|
104
|
+
order: index,
|
|
105
|
+
meta: problem.options ? { options: problem.options } : undefined,
|
|
106
|
+
})),
|
|
107
|
+
} : undefined,
|
|
108
|
+
},
|
|
109
|
+
include: {
|
|
110
|
+
questions: true,
|
|
48
111
|
},
|
|
49
112
|
});
|
|
50
113
|
}),
|
|
@@ -59,10 +122,37 @@ export const worksheets = router({
|
|
|
59
122
|
workspace: { ownerId: ctx.session.user.id },
|
|
60
123
|
},
|
|
61
124
|
include: { questions: true },
|
|
125
|
+
orderBy: { updatedAt: 'desc' },
|
|
62
126
|
});
|
|
63
127
|
if (!worksheet)
|
|
64
128
|
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
65
|
-
|
|
129
|
+
// Merge per-user progress into question.meta for compatibility with UI
|
|
130
|
+
const questionIds = worksheet.questions.map(q => q.id);
|
|
131
|
+
if (questionIds.length === 0)
|
|
132
|
+
return worksheet;
|
|
133
|
+
const progress = await ctx.db.worksheetQuestionProgress.findMany({
|
|
134
|
+
where: { userId: ctx.session.user.id, worksheetQuestionId: { in: questionIds } },
|
|
135
|
+
});
|
|
136
|
+
const progressByQuestionId = new Map(progress.map(p => [p.worksheetQuestionId, p]));
|
|
137
|
+
const merged = {
|
|
138
|
+
...worksheet,
|
|
139
|
+
questions: worksheet.questions.map(q => {
|
|
140
|
+
const p = progressByQuestionId.get(q.id);
|
|
141
|
+
if (!p)
|
|
142
|
+
return q;
|
|
143
|
+
const existingMeta = q.meta ? (typeof q.meta === 'object' ? q.meta : JSON.parse(q.meta)) : {};
|
|
144
|
+
return {
|
|
145
|
+
...q,
|
|
146
|
+
meta: {
|
|
147
|
+
...existingMeta,
|
|
148
|
+
completed: p.completed,
|
|
149
|
+
userAnswer: p.userAnswer,
|
|
150
|
+
completedAt: p.completedAt,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
155
|
+
return merged;
|
|
66
156
|
}),
|
|
67
157
|
// Add a question to a worksheet
|
|
68
158
|
createWorksheetQuestion: authedProcedure
|
|
@@ -70,6 +160,7 @@ export const worksheets = router({
|
|
|
70
160
|
worksheetId: z.string(),
|
|
71
161
|
prompt: z.string().min(1),
|
|
72
162
|
answer: z.string().optional(),
|
|
163
|
+
type: z.enum(['MULTIPLE_CHOICE', 'TEXT', 'NUMERIC', 'TRUE_FALSE', 'MATCHING', 'FILL_IN_THE_BLANK']).optional(),
|
|
73
164
|
difficulty: z.enum(['EASY', 'MEDIUM', 'HARD']).optional(),
|
|
74
165
|
order: z.number().int().optional(),
|
|
75
166
|
meta: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -85,6 +176,7 @@ export const worksheets = router({
|
|
|
85
176
|
artifactId: input.worksheetId,
|
|
86
177
|
prompt: input.prompt,
|
|
87
178
|
answer: input.answer,
|
|
179
|
+
type: (input.type ?? QuestionType.TEXT),
|
|
88
180
|
difficulty: (input.difficulty ?? Difficulty.MEDIUM),
|
|
89
181
|
order: input.order ?? 0,
|
|
90
182
|
meta: input.meta,
|
|
@@ -97,6 +189,7 @@ export const worksheets = router({
|
|
|
97
189
|
worksheetQuestionId: z.string(),
|
|
98
190
|
prompt: z.string().optional(),
|
|
99
191
|
answer: z.string().optional(),
|
|
192
|
+
type: z.enum(['MULTIPLE_CHOICE', 'TEXT', 'NUMERIC', 'TRUE_FALSE', 'MATCHING', 'FILL_IN_THE_BLANK']).optional(),
|
|
100
193
|
difficulty: z.enum(['EASY', 'MEDIUM', 'HARD']).optional(),
|
|
101
194
|
order: z.number().int().optional(),
|
|
102
195
|
meta: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -112,6 +205,7 @@ export const worksheets = router({
|
|
|
112
205
|
data: {
|
|
113
206
|
prompt: input.prompt ?? q.prompt,
|
|
114
207
|
answer: input.answer ?? q.answer,
|
|
208
|
+
type: (input.type ?? q.type),
|
|
115
209
|
difficulty: (input.difficulty ?? q.difficulty),
|
|
116
210
|
order: input.order ?? q.order,
|
|
117
211
|
meta: (input.meta ?? q.meta),
|
|
@@ -130,15 +224,231 @@ export const worksheets = router({
|
|
|
130
224
|
await ctx.db.worksheetQuestion.delete({ where: { id: input.worksheetQuestionId } });
|
|
131
225
|
return true;
|
|
132
226
|
}),
|
|
133
|
-
//
|
|
134
|
-
|
|
227
|
+
// Update problem completion status
|
|
228
|
+
updateProblemStatus: authedProcedure
|
|
229
|
+
.input(z.object({
|
|
230
|
+
problemId: z.string(),
|
|
231
|
+
completed: z.boolean(),
|
|
232
|
+
answer: z.string().optional(),
|
|
233
|
+
}))
|
|
234
|
+
.mutation(async ({ ctx, input }) => {
|
|
235
|
+
// Verify question ownership through worksheet
|
|
236
|
+
const question = await ctx.db.worksheetQuestion.findFirst({
|
|
237
|
+
where: {
|
|
238
|
+
id: input.problemId,
|
|
239
|
+
artifact: {
|
|
240
|
+
type: ArtifactType.WORKSHEET,
|
|
241
|
+
workspace: { ownerId: ctx.session.user.id },
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
if (!question)
|
|
246
|
+
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
247
|
+
// Upsert per-user progress row
|
|
248
|
+
const progress = await ctx.db.worksheetQuestionProgress.upsert({
|
|
249
|
+
where: {
|
|
250
|
+
worksheetQuestionId_userId: {
|
|
251
|
+
worksheetQuestionId: input.problemId,
|
|
252
|
+
userId: ctx.session.user.id,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
create: {
|
|
256
|
+
worksheetQuestionId: input.problemId,
|
|
257
|
+
userId: ctx.session.user.id,
|
|
258
|
+
completed: input.completed,
|
|
259
|
+
userAnswer: input.answer,
|
|
260
|
+
completedAt: input.completed ? new Date() : null,
|
|
261
|
+
attempts: 1,
|
|
262
|
+
},
|
|
263
|
+
update: {
|
|
264
|
+
completed: input.completed,
|
|
265
|
+
userAnswer: input.answer,
|
|
266
|
+
completedAt: input.completed ? new Date() : null,
|
|
267
|
+
attempts: { increment: 1 },
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
return progress;
|
|
271
|
+
}),
|
|
272
|
+
// Get current user's progress for all questions in a worksheet
|
|
273
|
+
getProgress: authedProcedure
|
|
135
274
|
.input(z.object({ worksheetId: z.string() }))
|
|
275
|
+
.query(async ({ ctx, input }) => {
|
|
276
|
+
// Verify worksheet ownership
|
|
277
|
+
const worksheet = await ctx.db.artifact.findFirst({
|
|
278
|
+
where: {
|
|
279
|
+
id: input.worksheetId,
|
|
280
|
+
type: ArtifactType.WORKSHEET,
|
|
281
|
+
workspace: { ownerId: ctx.session.user.id },
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
if (!worksheet)
|
|
285
|
+
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
286
|
+
const questions = await ctx.db.worksheetQuestion.findMany({
|
|
287
|
+
where: { artifactId: input.worksheetId },
|
|
288
|
+
select: { id: true },
|
|
289
|
+
});
|
|
290
|
+
const questionIds = questions.map(q => q.id);
|
|
291
|
+
const progress = await ctx.db.worksheetQuestionProgress.findMany({
|
|
292
|
+
where: {
|
|
293
|
+
userId: ctx.session.user.id,
|
|
294
|
+
worksheetQuestionId: { in: questionIds },
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
return progress;
|
|
298
|
+
}),
|
|
299
|
+
// Update a worksheet
|
|
300
|
+
update: authedProcedure
|
|
301
|
+
.input(z.object({
|
|
302
|
+
id: z.string(),
|
|
303
|
+
title: z.string().min(1).max(120).optional(),
|
|
304
|
+
description: z.string().optional(),
|
|
305
|
+
difficulty: z.enum(['EASY', 'MEDIUM', 'HARD']).optional(),
|
|
306
|
+
estimatedTime: z.string().optional(),
|
|
307
|
+
problems: z.array(z.object({
|
|
308
|
+
id: z.string().optional(),
|
|
309
|
+
question: z.string().min(1),
|
|
310
|
+
answer: z.string().min(1),
|
|
311
|
+
type: z.enum(['MULTIPLE_CHOICE', 'TEXT', 'NUMERIC', 'TRUE_FALSE', 'MATCHING', 'FILL_IN_THE_BLANK']).default('TEXT'),
|
|
312
|
+
options: z.array(z.string()).optional(),
|
|
313
|
+
})).optional(),
|
|
314
|
+
}))
|
|
315
|
+
.mutation(async ({ ctx, input }) => {
|
|
316
|
+
const { id, problems, ...updateData } = input;
|
|
317
|
+
// Verify worksheet ownership
|
|
318
|
+
const existingWorksheet = await ctx.db.artifact.findFirst({
|
|
319
|
+
where: {
|
|
320
|
+
id,
|
|
321
|
+
type: ArtifactType.WORKSHEET,
|
|
322
|
+
workspace: { ownerId: ctx.session.user.id },
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
if (!existingWorksheet)
|
|
326
|
+
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
327
|
+
// Handle questions update if provided
|
|
328
|
+
if (problems) {
|
|
329
|
+
// Delete existing questions and create new ones
|
|
330
|
+
await ctx.db.worksheetQuestion.deleteMany({
|
|
331
|
+
where: { artifactId: id },
|
|
332
|
+
});
|
|
333
|
+
await ctx.db.worksheetQuestion.createMany({
|
|
334
|
+
data: problems.map((problem, index) => ({
|
|
335
|
+
artifactId: id,
|
|
336
|
+
prompt: problem.question,
|
|
337
|
+
answer: problem.answer,
|
|
338
|
+
type: problem.type,
|
|
339
|
+
order: index,
|
|
340
|
+
meta: problem.options ? { options: problem.options } : undefined,
|
|
341
|
+
})),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
// Process update data
|
|
345
|
+
const processedUpdateData = {
|
|
346
|
+
...updateData,
|
|
347
|
+
difficulty: updateData.difficulty,
|
|
348
|
+
};
|
|
349
|
+
return ctx.db.artifact.update({
|
|
350
|
+
where: { id },
|
|
351
|
+
data: processedUpdateData,
|
|
352
|
+
include: {
|
|
353
|
+
questions: {
|
|
354
|
+
orderBy: { order: 'asc' },
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}),
|
|
359
|
+
// Delete a worksheet set and its questions
|
|
360
|
+
delete: authedProcedure
|
|
361
|
+
.input(z.object({ id: z.string() }))
|
|
136
362
|
.mutation(async ({ ctx, input }) => {
|
|
137
363
|
const deleted = await ctx.db.artifact.deleteMany({
|
|
138
|
-
where: { id: input.
|
|
364
|
+
where: { id: input.id, type: ArtifactType.WORKSHEET, workspace: { ownerId: ctx.session.user.id } },
|
|
139
365
|
});
|
|
140
366
|
if (deleted.count === 0)
|
|
141
367
|
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
142
368
|
return true;
|
|
143
369
|
}),
|
|
370
|
+
// Generate a worksheet from a user prompt
|
|
371
|
+
generateFromPrompt: authedProcedure
|
|
372
|
+
.input(z.object({
|
|
373
|
+
workspaceId: z.string(),
|
|
374
|
+
prompt: z.string().min(1),
|
|
375
|
+
numQuestions: z.number().int().min(1).max(20).default(8),
|
|
376
|
+
difficulty: z.enum(['easy', 'medium', 'hard']).default('medium'),
|
|
377
|
+
title: z.string().optional(),
|
|
378
|
+
estimatedTime: z.string().optional(),
|
|
379
|
+
}))
|
|
380
|
+
.mutation(async ({ ctx, input }) => {
|
|
381
|
+
const workspace = await ctx.db.workspace.findFirst({ where: { id: input.workspaceId, ownerId: ctx.session.user.id } });
|
|
382
|
+
if (!workspace)
|
|
383
|
+
throw new TRPCError({ code: 'NOT_FOUND' });
|
|
384
|
+
await PusherService.emitTaskComplete(input.workspaceId, 'worksheet_load_start', { source: 'prompt' });
|
|
385
|
+
const session = await aiSessionService.initSession(input.workspaceId);
|
|
386
|
+
await aiSessionService.setInstruction(session.id, `Create a worksheet with ${input.numQuestions} questions at ${input.difficulty} difficulty from this prompt. Return JSON.\n\nPrompt:\n${input.prompt}`);
|
|
387
|
+
await aiSessionService.startLLMSession(session.id);
|
|
388
|
+
const content = await aiSessionService.generateWorksheetQuestions(session.id, input.numQuestions, input.difficulty);
|
|
389
|
+
await PusherService.emitTaskComplete(input.workspaceId, 'worksheet_info', { contentLength: content.length });
|
|
390
|
+
const artifact = await ctx.db.artifact.create({
|
|
391
|
+
data: {
|
|
392
|
+
workspaceId: input.workspaceId,
|
|
393
|
+
type: ArtifactType.WORKSHEET,
|
|
394
|
+
title: input.title || `Worksheet - ${new Date().toLocaleString()}`,
|
|
395
|
+
createdById: ctx.session.user.id,
|
|
396
|
+
difficulty: (input.difficulty.toUpperCase()),
|
|
397
|
+
estimatedTime: input.estimatedTime,
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
try {
|
|
401
|
+
const worksheetData = JSON.parse(content);
|
|
402
|
+
let actualWorksheetData = worksheetData;
|
|
403
|
+
if (worksheetData.last_response) {
|
|
404
|
+
try {
|
|
405
|
+
actualWorksheetData = JSON.parse(worksheetData.last_response);
|
|
406
|
+
}
|
|
407
|
+
catch { }
|
|
408
|
+
}
|
|
409
|
+
const problems = actualWorksheetData.problems || actualWorksheetData.questions || actualWorksheetData || [];
|
|
410
|
+
for (let i = 0; i < Math.min(problems.length, input.numQuestions); i++) {
|
|
411
|
+
const problem = problems[i];
|
|
412
|
+
const prompt = problem.question || problem.prompt || `Question ${i + 1}`;
|
|
413
|
+
const answer = problem.answer || problem.solution || `Answer ${i + 1}`;
|
|
414
|
+
const type = problem.type || 'TEXT';
|
|
415
|
+
const options = problem.options || [];
|
|
416
|
+
await ctx.db.worksheetQuestion.create({
|
|
417
|
+
data: {
|
|
418
|
+
artifactId: artifact.id,
|
|
419
|
+
prompt,
|
|
420
|
+
answer,
|
|
421
|
+
difficulty: (input.difficulty.toUpperCase()),
|
|
422
|
+
order: i,
|
|
423
|
+
meta: {
|
|
424
|
+
type,
|
|
425
|
+
options: options.length > 0 ? options : undefined,
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
433
|
+
for (let i = 0; i < Math.min(lines.length, input.numQuestions); i++) {
|
|
434
|
+
const line = lines[i];
|
|
435
|
+
if (line.includes(' - ')) {
|
|
436
|
+
const [q, a] = line.split(' - ');
|
|
437
|
+
await ctx.db.worksheetQuestion.create({
|
|
438
|
+
data: {
|
|
439
|
+
artifactId: artifact.id,
|
|
440
|
+
prompt: q.trim(),
|
|
441
|
+
answer: a.trim(),
|
|
442
|
+
difficulty: (input.difficulty.toUpperCase()),
|
|
443
|
+
order: i,
|
|
444
|
+
meta: { type: 'TEXT' },
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
await PusherService.emitWorksheetComplete(input.workspaceId, artifact);
|
|
451
|
+
aiSessionService.deleteSession(session.id);
|
|
452
|
+
return { artifact };
|
|
453
|
+
}),
|
|
144
454
|
});
|
|
@@ -11,7 +11,37 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
11
11
|
transformer: true;
|
|
12
12
|
}, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
|
|
13
13
|
list: import("@trpc/server").TRPCQueryProcedure<{
|
|
14
|
-
input:
|
|
14
|
+
input: {
|
|
15
|
+
parentId?: string | undefined;
|
|
16
|
+
};
|
|
17
|
+
output: {
|
|
18
|
+
workspaces: {
|
|
19
|
+
id: string;
|
|
20
|
+
createdAt: Date;
|
|
21
|
+
updatedAt: Date;
|
|
22
|
+
ownerId: string;
|
|
23
|
+
title: string;
|
|
24
|
+
description: string | null;
|
|
25
|
+
folderId: string | null;
|
|
26
|
+
shareLink: string | null;
|
|
27
|
+
}[];
|
|
28
|
+
folders: {
|
|
29
|
+
name: string;
|
|
30
|
+
id: string;
|
|
31
|
+
createdAt: Date;
|
|
32
|
+
updatedAt: Date;
|
|
33
|
+
ownerId: string;
|
|
34
|
+
parentId: string | null;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
37
|
+
meta: object;
|
|
38
|
+
}>;
|
|
39
|
+
create: import("@trpc/server").TRPCMutationProcedure<{
|
|
40
|
+
input: {
|
|
41
|
+
name: string;
|
|
42
|
+
description?: string | undefined;
|
|
43
|
+
parentId?: string | undefined;
|
|
44
|
+
};
|
|
15
45
|
output: {
|
|
16
46
|
id: string;
|
|
17
47
|
createdAt: Date;
|
|
@@ -20,22 +50,22 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
20
50
|
title: string;
|
|
21
51
|
description: string | null;
|
|
22
52
|
folderId: string | null;
|
|
23
|
-
|
|
53
|
+
shareLink: string | null;
|
|
54
|
+
};
|
|
24
55
|
meta: object;
|
|
25
56
|
}>;
|
|
26
|
-
|
|
57
|
+
createFolder: import("@trpc/server").TRPCMutationProcedure<{
|
|
27
58
|
input: {
|
|
28
59
|
name: string;
|
|
29
|
-
|
|
60
|
+
parentId?: string | undefined;
|
|
30
61
|
};
|
|
31
62
|
output: {
|
|
63
|
+
name: string;
|
|
32
64
|
id: string;
|
|
33
65
|
createdAt: Date;
|
|
34
66
|
updatedAt: Date;
|
|
35
67
|
ownerId: string;
|
|
36
|
-
|
|
37
|
-
description: string | null;
|
|
38
|
-
folderId: string | null;
|
|
68
|
+
parentId: string | null;
|
|
39
69
|
};
|
|
40
70
|
meta: object;
|
|
41
71
|
}>;
|
|
@@ -44,6 +74,42 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
44
74
|
id: string;
|
|
45
75
|
};
|
|
46
76
|
output: {
|
|
77
|
+
folder: {
|
|
78
|
+
name: string;
|
|
79
|
+
id: string;
|
|
80
|
+
createdAt: Date;
|
|
81
|
+
updatedAt: Date;
|
|
82
|
+
ownerId: string;
|
|
83
|
+
parentId: string | null;
|
|
84
|
+
} | null;
|
|
85
|
+
uploads: {
|
|
86
|
+
meta: import("@prisma/client/runtime/library").JsonValue | null;
|
|
87
|
+
name: string;
|
|
88
|
+
id: string;
|
|
89
|
+
createdAt: Date;
|
|
90
|
+
userId: string;
|
|
91
|
+
workspaceId: string;
|
|
92
|
+
mimeType: string;
|
|
93
|
+
size: number;
|
|
94
|
+
bucket: string | null;
|
|
95
|
+
objectKey: string | null;
|
|
96
|
+
url: string | null;
|
|
97
|
+
checksum: string | null;
|
|
98
|
+
}[];
|
|
99
|
+
artifacts: {
|
|
100
|
+
id: string;
|
|
101
|
+
createdAt: Date;
|
|
102
|
+
updatedAt: Date;
|
|
103
|
+
title: string;
|
|
104
|
+
description: string | null;
|
|
105
|
+
workspaceId: string;
|
|
106
|
+
type: import("@prisma/client").$Enums.ArtifactType;
|
|
107
|
+
isArchived: boolean;
|
|
108
|
+
difficulty: import("@prisma/client").$Enums.Difficulty | null;
|
|
109
|
+
estimatedTime: string | null;
|
|
110
|
+
createdById: string | null;
|
|
111
|
+
}[];
|
|
112
|
+
} & {
|
|
47
113
|
id: string;
|
|
48
114
|
createdAt: Date;
|
|
49
115
|
updatedAt: Date;
|
|
@@ -51,6 +117,30 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
51
117
|
title: string;
|
|
52
118
|
description: string | null;
|
|
53
119
|
folderId: string | null;
|
|
120
|
+
shareLink: string | null;
|
|
121
|
+
};
|
|
122
|
+
meta: object;
|
|
123
|
+
}>;
|
|
124
|
+
share: import("@trpc/server").TRPCQueryProcedure<{
|
|
125
|
+
input: {
|
|
126
|
+
id: string;
|
|
127
|
+
};
|
|
128
|
+
output: {
|
|
129
|
+
shareLink: string | null;
|
|
130
|
+
} | undefined;
|
|
131
|
+
meta: object;
|
|
132
|
+
}>;
|
|
133
|
+
join: import("@trpc/server").TRPCMutationProcedure<{
|
|
134
|
+
input: {
|
|
135
|
+
shareLink: string;
|
|
136
|
+
};
|
|
137
|
+
output: {
|
|
138
|
+
id: string;
|
|
139
|
+
title: string;
|
|
140
|
+
description: string | null;
|
|
141
|
+
ownerId: string;
|
|
142
|
+
createdAt: Date;
|
|
143
|
+
updatedAt: Date;
|
|
54
144
|
};
|
|
55
145
|
meta: object;
|
|
56
146
|
}>;
|
|
@@ -68,6 +158,7 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
68
158
|
title: string;
|
|
69
159
|
description: string | null;
|
|
70
160
|
folderId: string | null;
|
|
161
|
+
shareLink: string | null;
|
|
71
162
|
};
|
|
72
163
|
meta: object;
|
|
73
164
|
}>;
|
|
@@ -78,6 +169,30 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
78
169
|
output: boolean;
|
|
79
170
|
meta: object;
|
|
80
171
|
}>;
|
|
172
|
+
getFolderInformation: import("@trpc/server").TRPCQueryProcedure<{
|
|
173
|
+
input: {
|
|
174
|
+
id: string;
|
|
175
|
+
};
|
|
176
|
+
output: {
|
|
177
|
+
folder: {
|
|
178
|
+
name: string;
|
|
179
|
+
id: string;
|
|
180
|
+
createdAt: Date;
|
|
181
|
+
updatedAt: Date;
|
|
182
|
+
ownerId: string;
|
|
183
|
+
parentId: string | null;
|
|
184
|
+
};
|
|
185
|
+
parents: {
|
|
186
|
+
name: string;
|
|
187
|
+
id: string;
|
|
188
|
+
createdAt: Date;
|
|
189
|
+
updatedAt: Date;
|
|
190
|
+
ownerId: string;
|
|
191
|
+
parentId: string | null;
|
|
192
|
+
}[];
|
|
193
|
+
};
|
|
194
|
+
meta: object;
|
|
195
|
+
}>;
|
|
81
196
|
uploadFiles: import("@trpc/server").TRPCMutationProcedure<{
|
|
82
197
|
input: {
|
|
83
198
|
id: string;
|
|
@@ -101,4 +216,44 @@ export declare const workspace: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
101
216
|
output: boolean;
|
|
102
217
|
meta: object;
|
|
103
218
|
}>;
|
|
219
|
+
uploadAndAnalyzeMedia: import("@trpc/server").TRPCMutationProcedure<{
|
|
220
|
+
input: {
|
|
221
|
+
workspaceId: string;
|
|
222
|
+
file: {
|
|
223
|
+
filename: string;
|
|
224
|
+
contentType: string;
|
|
225
|
+
size: number;
|
|
226
|
+
content: string;
|
|
227
|
+
};
|
|
228
|
+
generateStudyGuide?: boolean | undefined;
|
|
229
|
+
generateFlashcards?: boolean | undefined;
|
|
230
|
+
generateWorksheet?: boolean | undefined;
|
|
231
|
+
};
|
|
232
|
+
output: {
|
|
233
|
+
filename: string;
|
|
234
|
+
artifacts: {
|
|
235
|
+
studyGuide: any | null;
|
|
236
|
+
flashcards: any | null;
|
|
237
|
+
worksheet: any | null;
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
meta: object;
|
|
241
|
+
}>;
|
|
242
|
+
search: import("@trpc/server").TRPCQueryProcedure<{
|
|
243
|
+
input: {
|
|
244
|
+
query: string;
|
|
245
|
+
limit?: number | undefined;
|
|
246
|
+
};
|
|
247
|
+
output: {
|
|
248
|
+
id: string;
|
|
249
|
+
createdAt: Date;
|
|
250
|
+
updatedAt: Date;
|
|
251
|
+
ownerId: string;
|
|
252
|
+
title: string;
|
|
253
|
+
description: string | null;
|
|
254
|
+
folderId: string | null;
|
|
255
|
+
shareLink: string | null;
|
|
256
|
+
}[];
|
|
257
|
+
meta: object;
|
|
258
|
+
}>;
|
|
104
259
|
}>>;
|