@goscribe/server 1.1.6 → 1.2.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.
@@ -335,7 +335,7 @@ export class FlashcardProgressService {
335
335
  },
336
336
  });
337
337
 
338
- console.log('allFlashcards', allFlashcards.length);
338
+ // allFlashcards count logged for debugging if needed
339
339
 
340
340
  const TAKE_NUMBER = (allFlashcards.length > 10) ? 10 : allFlashcards.length;
341
341
 
@@ -374,9 +374,7 @@ export class FlashcardProgressService {
374
374
  take: TAKE_NUMBER,
375
375
  });
376
376
 
377
- console.log('TAKE_NUMBER', TAKE_NUMBER);
378
- console.log('TAKE_NUMBER - progressRecords.length', TAKE_NUMBER - progressRecords.length);
379
- console.log('progressRecords', progressRecords.map((progress) => progress.flashcard.id));
377
+ // Due card selection: TAKE_NUMBER=${TAKE_NUMBER}, existing=${progressRecords.length}
380
378
 
381
379
  // Get flashcard IDs that already have progress records
382
380
  const flashcardIdsWithProgress = new Set(
@@ -409,8 +407,7 @@ export class FlashcardProgressService {
409
407
  };
410
408
  });
411
409
 
412
- console.log('progressRecordsPadding', progressRecordsPadding.length);
413
- console.log('progressRecords', progressRecords.length);
410
+ // Combined: ${progressRecords.length} due + ${progressRecordsPadding.length} padding cards
414
411
  const selectedCards = [...progressRecords, ...progressRecordsPadding];
415
412
 
416
413
  // Build result array: include progress records and non-studied flashcards
@@ -1,416 +0,0 @@
1
- // import { z } from 'zod';
2
- // import { TRPCError } from '@trpc/server';
3
- // import { router, authedProcedure } from '../trpc.js';
4
- // import OpenAI from 'openai';
5
- // import fs from 'fs';
6
- // import path from 'path';
7
- // import { v4 as uuidv4 } from 'uuid';
8
-
9
- // // Prisma enum values mapped manually to avoid type import issues in ESM
10
- // const ArtifactType = {
11
- // STUDY_GUIDE: 'STUDY_GUIDE',
12
- // FLASHCARD_SET: 'FLASHCARD_SET',
13
- // WORKSHEET: 'WORKSHEET',
14
- // MEETING_SUMMARY: 'MEETING_SUMMARY',
15
- // PODCAST_EPISODE: 'PODCAST_EPISODE',
16
- // } as const;
17
-
18
- // // Initialize OpenAI client
19
- // const openai = new OpenAI({
20
- // apiKey: process.env.OPENAI_API_KEY,
21
- // });
22
-
23
- // // Meeting summary schema for structured data
24
- // const meetingSchema = z.object({
25
- // title: z.string(),
26
- // participants: z.array(z.string()),
27
- // date: z.string(),
28
- // duration: z.string().optional(),
29
- // agenda: z.array(z.string()).optional(),
30
- // transcript: z.string().optional(),
31
- // notes: z.string().optional(),
32
- // });
33
-
34
- // export const meetingSummarize = router({
35
- // // List all meeting summaries for a workspace
36
- // listSummaries: authedProcedure
37
- // .input(z.object({ workspaceId: z.string() }))
38
- // .query(async ({ ctx, input }) => {
39
- // const workspace = await ctx.db.workspace.findFirst({
40
- // where: { id: input.workspaceId, ownerId: ctx.session.user.id },
41
- // });
42
- // if (!workspace) throw new TRPCError({ code: 'NOT_FOUND' });
43
-
44
- // return ctx.db.artifact.findMany({
45
- // where: {
46
- // workspaceId: input.workspaceId,
47
- // type: ArtifactType.MEETING_SUMMARY
48
- // },
49
- // include: {
50
- // versions: {
51
- // orderBy: { version: 'desc' },
52
- // take: 1, // Get only the latest version
53
- // },
54
- // },
55
- // orderBy: { updatedAt: 'desc' },
56
- // });
57
- // }),
58
-
59
- // // Get a specific meeting summary
60
- // getSummary: authedProcedure
61
- // .input(z.object({ summaryId: z.string() }))
62
- // .query(async ({ ctx, input }) => {
63
- // const summary = await ctx.db.artifact.findFirst({
64
- // where: {
65
- // id: input.summaryId,
66
- // type: ArtifactType.MEETING_SUMMARY,
67
- // workspace: { ownerId: ctx.session.user.id }
68
- // },
69
- // include: {
70
- // versions: {
71
- // orderBy: { version: 'desc' },
72
- // take: 1,
73
- // },
74
- // },
75
- // });
76
- // if (!summary) throw new TRPCError({ code: 'NOT_FOUND' });
77
- // return summary;
78
- // }),
79
-
80
- // // Upload and process audio/video file
81
- // uploadFile: authedProcedure
82
- // .input(z.object({
83
- // workspaceId: z.string(),
84
- // fileName: z.string(),
85
- // fileBuffer: z.string(), // Base64 encoded file
86
- // mimeType: z.string(),
87
- // title: z.string().optional(),
88
- // }))
89
- // .mutation(async ({ ctx, input }) => {
90
- // const workspace = await ctx.db.workspace.findFirst({
91
- // where: { id: input.workspaceId, ownerId: ctx.session.user.id },
92
- // });
93
- // if (!workspace) throw new TRPCError({ code: 'NOT_FOUND' });
94
-
95
- // // Validate file type
96
- // const allowedTypes = ['audio/mpeg', 'audio/mp3', 'video/mp4', 'audio/wav', 'audio/m4a'];
97
- // if (!allowedTypes.includes(input.mimeType)) {
98
- // throw new TRPCError({
99
- // code: 'BAD_REQUEST',
100
- // message: 'Unsupported file type. Please upload MP3, MP4, WAV, or M4A files.'
101
- // });
102
- // }
103
-
104
- // try {
105
- // // Create temporary file
106
- // const tempDir = path.join(process.cwd(), 'temp');
107
- // if (!fs.existsSync(tempDir)) {
108
- // fs.mkdirSync(tempDir, { recursive: true });
109
- // }
110
-
111
- // const fileId = uuidv4();
112
- // const fileExtension = path.extname(input.fileName);
113
- // const tempFilePath = path.join(tempDir, `${fileId}${fileExtension}`);
114
-
115
- // // Write buffer to temporary file
116
- // const fileBuffer = Buffer.from(input.fileBuffer, 'base64');
117
- // fs.writeFileSync(tempFilePath, fileBuffer);
118
-
119
- // // Transcribe audio using OpenAI Whisper
120
- // const transcript = await openai.audio.transcriptions.create({
121
- // file: fs.createReadStream(tempFilePath),
122
- // model: 'whisper-1',
123
- // response_format: 'text',
124
- // });
125
-
126
- // // Generate meeting summary using GPT
127
- // const summaryResponse = await openai.chat.completions.create({
128
- // model: 'gpt-4-turbo-preview',
129
- // messages: [
130
- // {
131
- // role: 'system',
132
- // content: `You are a meeting summarizer. Given a meeting transcript, create a comprehensive summary that includes:
133
- // 1. Meeting title/topic
134
- // 2. Key participants mentioned
135
- // 3. Main discussion points
136
- // 4. Action items
137
- // 5. Decisions made
138
- // 6. Next steps
139
- // Format the response as JSON with the following structure:
140
- // {
141
- // "title": "Meeting title",
142
- // "participants": ["participant1", "participant2"],
143
- // "keyPoints": ["point1", "point2"],
144
- // "actionItems": ["action1", "action2"],
145
- // "decisions": ["decision1", "decision2"],
146
- // "nextSteps": ["step1", "step2"],
147
- // "summary": "Overall meeting summary"
148
- // }`
149
- // },
150
- // {
151
- // role: 'user',
152
- // content: `Please summarize this meeting transcript: ${transcript}`
153
- // }
154
- // ],
155
- // });
156
-
157
- // let summaryData;
158
- // try {
159
- // summaryData = JSON.parse(summaryResponse.choices[0]?.message?.content || '{}');
160
- // } catch (parseError) {
161
- // // Fallback if JSON parsing fails
162
- // summaryData = {
163
- // title: input.title || 'Meeting Summary',
164
- // participants: [],
165
- // keyPoints: [],
166
- // actionItems: [],
167
- // decisions: [],
168
- // nextSteps: [],
169
- // summary: summaryResponse.choices[0]?.message?.content || 'Unable to generate summary'
170
- // };
171
- // }
172
-
173
- // // Create artifact in database
174
- // const artifact = await ctx.db.artifact.create({
175
- // data: {
176
- // workspaceId: input.workspaceId,
177
- // type: ArtifactType.MEETING_SUMMARY,
178
- // title: summaryData.title || input.title || 'Meeting Summary',
179
- // content: JSON.stringify({
180
- // originalFileName: input.fileName,
181
- // transcript: transcript,
182
- // ...summaryData
183
- // }),
184
- // },
185
- // });
186
-
187
- // // Create initial version
188
- // await ctx.db.artifactVersion.create({
189
- // data: {
190
- // artifactId: artifact.id,
191
- // version: 1,
192
- // content: artifact.content,
193
- // },
194
- // });
195
-
196
- // // Clean up temporary file
197
- // fs.unlinkSync(tempFilePath);
198
-
199
- // return {
200
- // id: artifact.id,
201
- // title: artifact.title,
202
- // summary: summaryData,
203
- // transcript: transcript,
204
- // };
205
-
206
- // } catch (error) {
207
- // console.error('Error processing meeting file:', error);
208
- // throw new TRPCError({
209
- // code: 'INTERNAL_SERVER_ERROR',
210
- // message: 'Failed to process meeting file'
211
- // });
212
- // }
213
- // }),
214
-
215
- // // Process meeting data from schema
216
- // processSchema: authedProcedure
217
- // .input(z.object({
218
- // workspaceId: z.string(),
219
- // meetingData: meetingSchema,
220
- // }))
221
- // .mutation(async ({ ctx, input }) => {
222
- // const workspace = await ctx.db.workspace.findFirst({
223
- // where: { id: input.workspaceId, ownerId: ctx.session.user.id },
224
- // });
225
- // if (!workspace) throw new TRPCError({ code: 'NOT_FOUND' });
226
-
227
- // try {
228
- // // Create content for AI processing
229
- // const meetingContent = `
230
- // Meeting Title: ${input.meetingData.title}
231
- // Participants: ${input.meetingData.participants.join(', ')}
232
- // Date: ${input.meetingData.date}
233
- // Duration: ${input.meetingData.duration || 'Not specified'}
234
- // Agenda: ${input.meetingData.agenda?.join(', ') || 'Not provided'}
235
- // Notes: ${input.meetingData.notes || 'Not provided'}
236
- // Transcript: ${input.meetingData.transcript || 'Not provided'}
237
- // `;
238
-
239
- // // Generate enhanced summary using GPT
240
- // const summaryResponse = await openai.chat.completions.create({
241
- // model: 'gpt-4-turbo-preview',
242
- // messages: [
243
- // {
244
- // role: 'system',
245
- // content: `You are a meeting summarizer. Given meeting information, create a comprehensive summary that includes:
246
- // 1. Key discussion points
247
- // 2. Action items
248
- // 3. Decisions made
249
- // 4. Next steps
250
- // 5. Important insights
251
- // Format the response as JSON with the following structure:
252
- // {
253
- // "keyPoints": ["point1", "point2"],
254
- // "actionItems": ["action1", "action2"],
255
- // "decisions": ["decision1", "decision2"],
256
- // "nextSteps": ["step1", "step2"],
257
- // "insights": ["insight1", "insight2"],
258
- // "summary": "Overall meeting summary"
259
- // }`
260
- // },
261
- // {
262
- // role: 'user',
263
- // content: `Please analyze and summarize this meeting information: ${meetingContent}`
264
- // }
265
- // ],
266
- // });
267
-
268
- // let summaryData;
269
- // try {
270
- // summaryData = JSON.parse(summaryResponse.choices[0]?.message?.content || '{}');
271
- // } catch (parseError) {
272
- // // Fallback if JSON parsing fails
273
- // summaryData = {
274
- // keyPoints: [],
275
- // actionItems: [],
276
- // decisions: [],
277
- // nextSteps: [],
278
- // insights: [],
279
- // summary: summaryResponse.choices[0]?.message?.content || 'Unable to generate summary'
280
- // };
281
- // }
282
-
283
- // // Create artifact in database
284
- // const artifact = await ctx.db.artifact.create({
285
- // data: {
286
- // workspaceId: input.workspaceId,
287
- // type: ArtifactType.MEETING_SUMMARY,
288
- // title: input.meetingData.title,
289
- // content: JSON.stringify({
290
- // originalData: input.meetingData,
291
- // ...summaryData
292
- // }),
293
- // },
294
- // });
295
-
296
- // // Create initial version
297
- // await ctx.db.artifactVersion.create({
298
- // data: {
299
- // artifactId: artifact.id,
300
- // version: 1,
301
- // content: artifact.content,
302
- // },
303
- // });
304
-
305
- // return {
306
- // id: artifact.id,
307
- // title: artifact.title,
308
- // summary: summaryData,
309
- // originalData: input.meetingData,
310
- // };
311
-
312
- // } catch (error) {
313
- // console.error('Error processing meeting schema:', error);
314
- // throw new TRPCError({
315
- // code: 'INTERNAL_SERVER_ERROR',
316
- // message: 'Failed to process meeting data'
317
- // });
318
- // }
319
- // }),
320
-
321
- // // Update an existing meeting summary
322
- // updateSummary: authedProcedure
323
- // .input(z.object({
324
- // summaryId: z.string(),
325
- // title: z.string().optional(),
326
- // content: z.string().optional(),
327
- // }))
328
- // .mutation(async ({ ctx, input }) => {
329
- // const summary = await ctx.db.artifact.findFirst({
330
- // where: {
331
- // id: input.summaryId,
332
- // type: ArtifactType.MEETING_SUMMARY,
333
- // workspace: { ownerId: ctx.session.user.id }
334
- // },
335
- // include: {
336
- // versions: {
337
- // orderBy: { version: 'desc' },
338
- // take: 1,
339
- // },
340
- // },
341
- // });
342
-
343
- // if (!summary) throw new TRPCError({ code: 'NOT_FOUND' });
344
-
345
- // // Update artifact
346
- // const updatedArtifact = await ctx.db.artifact.update({
347
- // where: { id: input.summaryId },
348
- // data: {
349
- // title: input.title ?? summary.title,
350
- // content: input.content ?? summary.content,
351
- // updatedAt: new Date(),
352
- // },
353
- // });
354
-
355
- // // Create new version if content changed
356
- // if (input.content && input.content !== summary.content) {
357
- // const latestVersion = summary.versions[0]?.version || 0;
358
- // await ctx.db.artifactVersion.create({
359
- // data: {
360
- // artifactId: input.summaryId,
361
- // version: latestVersion + 1,
362
- // content: input.content,
363
- // },
364
- // });
365
- // }
366
-
367
- // return updatedArtifact;
368
- // }),
369
-
370
- // // Delete a meeting summary
371
- // deleteSummary: authedProcedure
372
- // .input(z.object({ summaryId: z.string() }))
373
- // .mutation(async ({ ctx, input }) => {
374
- // const summary = await ctx.db.artifact.findFirst({
375
- // where: {
376
- // id: input.summaryId,
377
- // type: ArtifactType.MEETING_SUMMARY,
378
- // workspace: { ownerId: ctx.session.user.id }
379
- // },
380
- // });
381
-
382
- // if (!summary) throw new TRPCError({ code: 'NOT_FOUND' });
383
-
384
- // // Delete associated versions first
385
- // await ctx.db.artifactVersion.deleteMany({
386
- // where: { artifactId: input.summaryId },
387
- // });
388
-
389
- // // Delete the artifact
390
- // await ctx.db.artifact.delete({
391
- // where: { id: input.summaryId },
392
- // });
393
-
394
- // return true;
395
- // }),
396
-
397
- // // Get meeting versions/history
398
- // getVersions: authedProcedure
399
- // .input(z.object({ summaryId: z.string() }))
400
- // .query(async ({ ctx, input }) => {
401
- // const summary = await ctx.db.artifact.findFirst({
402
- // where: {
403
- // id: input.summaryId,
404
- // type: ArtifactType.MEETING_SUMMARY,
405
- // workspace: { ownerId: ctx.session.user.id }
406
- // },
407
- // });
408
-
409
- // if (!summary) throw new TRPCError({ code: 'NOT_FOUND' });
410
-
411
- // return ctx.db.artifactVersion.findMany({
412
- // where: { artifactId: input.summaryId },
413
- // orderBy: { version: 'desc' },
414
- // });
415
- // }),
416
- // });