feat: add grammar check functionality and enhance quiz schema

- Introduced a new 'testCheckGrammar' field in DocumentSchema to facilitate grammar checking for documents, leveraging the document service for processing.
- Updated DocumentService to implement grammar checking logic, including caching results and publishing suggestions.
- Enhanced QuizSchema by adding filter arguments for quiz attempts, allowing for more flexible data retrieval based on user and quiz IDs.
- Cleaned up whitespace and improved error handling in quiz attempt creation to ensure better user feedback.

These changes improve the document editing experience and enhance the quiz feature's data handling capabilities.
This commit is contained in:
2024-12-11 22:36:35 +07:00
parent 4168bff1e8
commit 3652fda7d3
7 changed files with 72 additions and 43 deletions

View File

@@ -197,6 +197,16 @@ export class DocumentSchema extends PothosSchema {
},
}),
testCheckGrammar: t.field({
type: 'Boolean',
resolve: async (_query, _args, ctx: SchemaContext) => {
const documentId = '0a07abe1-4d21-4530-85b9-ed128bfd8f9e'
const pageId = 0
await this.documentService.checkGrammarForPage(documentId, pageId)
return true
},
}),
// exportDocument: t.field({
// type: this.DocumentExportObject(),
// args: {

View File

@@ -98,51 +98,50 @@ export class DocumentService {
}
// check grammar for a page by parallely send each sentence to OpenAI service as text and get the result, after that return the result as delta and publish the result to the document
// async checkGrammarForPage(documentId: string, pageId: number): Promise<void> {
// const sentenceDelta = await this.pageToSentence(documentId, pageId)
async checkGrammarForPage(documentId: string, pageId: number): Promise<void> {
const sentenceDelta = await this.pageToSentence(documentId, pageId)
// // Extract the entire page content as a single text
// const pageText = sentenceDelta.ops
// .filter((op) => typeof op.insert === 'string')
// .map((op) => op.insert as string)
// .join(' ')
// Extract the entire page content as a single text
const pageText = sentenceDelta.ops
.filter((op) => typeof op.insert === 'string')
.map((op) => op.insert as string)
.join(' ')
// // Create a unique cache key for the entire page
// const cacheKey = `grammar_check:${documentId}:${pageId}`
// Create a unique cache key for the entire page
const cacheKey = `grammar_check:${documentId}:${pageId}`
// // Try to get cached result first
// const cachedResult = await this.redis.get(cacheKey)
// Try to get cached result first
const cachedResult = await this.redis.get(cacheKey)
// if (cachedResult) {
// Logger.log('Cached grammar check result exists', 'Grammar Check')
// return
// }
// // Process the entire page text
// const grammarCheckResult = await this.openai.processText(pageText, 0, PromptType.CHECK_GRAMMAR)
// if (!grammarCheckResult.result) {
// return
// }
// // Cache the result
// await this.redis.setPermanent(cacheKey, JSON.stringify(grammarCheckResult))
// // Calculate diff between original page and corrected page
// const diff = await this.diff(pageText, grammarCheckResult.result)
// // Build payload
// // Publish the result to the subscriber
// this.pubSub.publish(`${DocumentEvent.AI_SUGGESTION}.${documentId}.${pageId}`, payload)
// }
// async diff(original: string, corrected: string): Promise<Delta> {
// const originalDelta = new Delta().insert(original)
// const correctedDelta = new Delta().insert(corrected)
// const diff = originalDelta.diff(correctedDelta)
// Logger.log(diff, 'diff')
// return diff
// }
if (cachedResult) {
Logger.log('Cached grammar check result exists', 'Grammar Check')
return
}
// Process the entire page text
const grammarCheckResult = await this.openai.processText(pageText, 0, PromptType.CHECK_GRAMMAR)
if (!grammarCheckResult.result) {
return
}
// Cache the result
await this.redis.setPermanent(cacheKey, JSON.stringify(grammarCheckResult))
// Calculate diff between original page and corrected page
const diff = await this.diff(pageText, grammarCheckResult.result)
// Build payload
// Publish the result to the subscriber
this.pubSub.publish(`${DocumentEvent.AI_SUGGESTION}.${documentId}.${pageId}`, payload)
}
async diff(original: string, corrected: string): Promise<Delta> {
const originalDelta = new Delta().insert(original)
const correctedDelta = new Delta().insert(corrected)
const diff = originalDelta.diff(correctedDelta)
Logger.log(diff, 'diff')
return diff
}
}

View File

@@ -96,6 +96,7 @@ export class PersonalMilestoneSchema extends PothosSchema {
})
},
}),
}))
}
}

View File

@@ -269,10 +269,18 @@ export class QuizSchema extends PothosSchema {
quizAttempts: t.prismaField({
type: [this.quizAttempt()],
args: {
filter: t.arg({
type: this.builder.generator.getWhere('QuizAttempt'),
required: false,
}),
quizId: t.arg({
type: 'String',
required: false,
}),
userId: t.arg({
type: 'String',
required: false,
}),
},
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) {
@@ -292,10 +300,15 @@ export class QuizSchema extends PothosSchema {
return await this.prisma.quizAttempt.findMany({
...query,
where: {
...args.filter,
quiz: {
centerMentorId: centerMentor.mentorId,
},
...(args.quizId ? [{ quizId: args.quizId }] : []),
...(args.userId ? [{ quizId: args.userId }] : []),
},
orderBy: {
createdAt: 'desc',
},
})
}
@@ -307,6 +320,9 @@ export class QuizSchema extends PothosSchema {
userId: ctx.http.me.id,
...(args.quizId ? [{ quizId: args.quizId }] : []),
},
orderBy: {
createdAt: 'desc',
},
})
}
},
@@ -407,6 +423,7 @@ export class QuizSchema extends PothosSchema {
if (!quiz) {
throw new Error('Quiz not found')
}
try {
return await this.prisma.quizAttempt.create({
...query,
data: {
@@ -415,6 +432,9 @@ export class QuizSchema extends PothosSchema {
user: { connect: { id: ctx.http.me.id } },
},
})
} catch (_error) {
throw new Error('Quiz attempt already exists')
}
},
}),
}))

View File

@@ -266,7 +266,6 @@ export class ScheduleSchema extends PothosSchema {
if (!ctx.http?.me?.id) {
throw new Error('User not found')
}
Logger.log(`ctx.http.me.role: ${ctx.http.me.role}`)
// use case 1: customer query schedules where customer is participant
if (ctx.http.me.role === Role.CUSTOMER) {
const schedules = await this.prisma.schedule.findMany({

File diff suppressed because one or more lines are too long