Files
epess-web-backend/src/Document/document.service.ts
Ly Tuan Kiet 871f24edb0 chore: update dependencies and enhance document schema
- Updated package.json and package-lock.json to include the new dependency 'quill-to-pdf' for improved document export functionality.
- Modified DocumentSchema to introduce a new 'DocumentExportObject' type, facilitating document export operations.
- Cleaned up commented-out code in document.service.ts and minio.service.ts for better readability and maintainability.
- Adjusted quiz schema to expose user input and questions as JSON types, enhancing data flexibility.
- Updated workshop subscription logic to maintain accurate participant counts upon new subscriptions.

These changes improve the overall functionality and maintainability of the project, ensuring better document handling and schema consistency.
2024-12-11 16:31:16 +07:00

149 lines
5.4 KiB
TypeScript

import { Inject, Injectable, forwardRef } from '@nestjs/common'
import { Logger } from '@nestjs/common'
import Delta, { Op } from 'quill-delta'
import { OpenaiService, PromptType } from 'src/OpenAI/openai.service'
import { PrismaService } from 'src/Prisma/prisma.service'
import { PubSubService } from 'src/PubSub/pubsub.service'
import { RedisService } from 'src/Redis/redis.service'
import { MinioService } from '../Minio/minio.service'
import { DocumentEvent } from './document.event'
import { DocumentDelta } from './document.type'
@Injectable()
export class DocumentService {
constructor(
private readonly prisma: PrismaService,
private readonly minio: MinioService,
private readonly openai: OpenaiService,
private readonly redis: RedisService,
private readonly pubSub: PubSubService,
) {}
// page to list paragraph as delta
async pageToParagraph(content: Delta): Promise<Delta> {
// Create a new Delta to store paragraphs
const paragraphDelta = new Delta()
// Iterate through the operations in the content Delta
for (const op of content.ops) {
// If the operation is a string insert
if (typeof op.insert === 'string') {
// Split the text by newline characters
const paragraphs = op.insert.split('\n').filter((p) => p.trim() !== '')
// Add each non-empty paragraph as a separate insert with a newline
paragraphs.forEach((paragraph, index) => {
paragraphDelta.insert(paragraph)
// Add a newline after each paragraph except the last one
if (index < paragraphs.length - 1) {
paragraphDelta.insert('\n')
}
})
} else {
// If the operation is not a string (e.g., an embedded object),
// add it to the paragraphDelta as-is
paragraphDelta.push(op)
}
}
return paragraphDelta
}
async paragraphToSentence(content: Delta): Promise<Delta> {
// Create a new Delta to store sentences
const sentenceDelta = new Delta()
// Iterate through the operations in the content Delta
for (const op of content.ops) {
// If the operation is a string insert
if (typeof op.insert === 'string') {
// Split the text into paragraphs first
const paragraphs = op.insert.split('\n').filter((p) => p.trim() !== '')
paragraphs.forEach((paragraph, paragraphIndex) => {
// Split paragraph into sentences using regex
// This handles common sentence-ending punctuation: . ! ?
const sentences = paragraph.split(/(?<=[.!?])\s+/).filter((s) => s.trim() !== '')
sentences.forEach((sentence, sentenceIndex) => {
sentenceDelta.insert(sentence.trim())
// Add a newline after each sentence except the last one in the paragraph
if (sentenceIndex < sentences.length - 1) {
sentenceDelta.insert('\n')
}
})
// Add a newline between paragraphs, except after the last paragraph
if (paragraphIndex < paragraphs.length - 1) {
sentenceDelta.insert('\n')
}
})
} else {
// If the operation is not a string (e.g., an embedded object),
// add it to the sentenceDelta as-is
sentenceDelta.push(op)
}
}
return sentenceDelta
}
async pageToSentence(documentId: string, pageId: number): Promise<Delta> {
const content = await this.minio.getDocumentContent(documentId, pageId)
const paragraphDelta = await this.pageToParagraph(content)
const sentenceDelta = await this.paragraphToSentence(paragraphDelta)
return sentenceDelta
}
// 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)
// // 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}`
// // 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
// }
}