Update dependencies in package.json and package-lock.json, refactor CronService to include notification handling for schedule expirations, and enhance DocumentSchema with OpenAI integration for document editing suggestions. Additionally, modify GraphqlModule to include PubSubModule for real-time notifications and improve datetime utility functions for better date formatting. Update epess-database subproject reference to indicate a dirty state.

This commit is contained in:
2024-11-30 16:41:47 +07:00
parent 7cff5069de
commit a619c95efc
17 changed files with 971 additions and 863 deletions

View File

@@ -0,0 +1,156 @@
---
title: Delta
---
Deltas are a simple, yet expressive format that can be used to describe Quill's contents and changes. The format is a strict subset of JSON, is human readable, and easily parsible by machines. Deltas can describe any Quill document, includes all text and formatting information, without the ambiguity and complexity of HTML.
<Hint>
Don't be confused by its name <em>Delta</em>&mdash;Deltas represents both documents and changes to documents. If you think of Deltas as the instructions from going from one document to another, the way Deltas represent a document is by expressing the instructions starting from an empty document.
</Hint>
Deltas are implemented as a separate [standalone library](https://github.com/quilljs/delta/), allowing its use outside of Quill. It is suitable for [Operational Transform](https://en.wikipedia.org/wiki/Operational_transformation) and can be used in realtime, Google Docs like applications. For a more in depth explanation behind Deltas, see [Designing the Delta Format](/guides/designing-the-delta-format/).
<Hint>
It is not recommended to construct Deltas by hand&mdash;rather use the chainable [`insert()`](https://github.com/quilljs/delta#insert), [`delete()`](https://github.com/quilljs/delta#delete), and [`retain()`](https://github.com/quilljs/delta#retain) methods to create new Deltas. You can use [`import()`](/docs/api/#import) to access Delta from Quill.
</Hint>
## Document
The Delta format is almost entirely self-explanatory&mdash;the example below describes the string "Gandalf the Grey" where "Gandalf" is bolded and "Grey" is colored #cccccc.
```javascript
{
ops: [
{ insert: 'Gandalf', attributes: { bold: true } },
{ insert: ' the ' },
{ insert: 'Grey', attributes: { color: '#cccccc' } }
]
}
```
As its name would imply, describing content is actually a special case for Deltas. The above example is more specifically instructions to insert a bolded string "Gandalf", an unformatted string " the ", followed by the string "Grey" colored #cccccc. When Deltas are used to describe content, it can be thought of as the content that would be created if the Delta was applied to an empty document.
Since Deltas are a data format, there is no inherent meaning to the values of `attribute` keypairs. For example, there is nothing in the Delta format that dictates color value must be in hex&mdash;this is a choice that Quill makes, and can be modified if desired with [Parchment](https://github.com/quilljs/parchment/).
### Embeds
For non-text content such as images or formulas, the insert key can be an object. The object should have one key, which will be used to determine its type. This is the `blotName` if you are building custom content with [Parchment](https://github.com/quilljs/parchment/). Like text, embeds can still have an `attributes` key to describe formatting to be applied to the embed. All embeds have a length of one.
```javascript
{
ops: [{
// An image link
insert: {
image: 'https://quilljs.com/assets/images/icon.png'
},
attributes: {
link: 'https://quilljs.com'
}
}]
}
```
### Line Formatting
Attributes associated with a newline character describes formatting for that line.
```javascript
{
ops: [
{ insert: 'The Two Towers' },
{ insert: '\n', attributes: { header: 1 } },
{ insert: 'Aragorn sped on up the hill.\n' }
]
}
```
All Quill documents must end with a newline character, even if there is no formatting applied to the last line. This way, you will always have a character position to apply line formatting to.
Many line formats are exclusive. For example Quill does not allow a line to simultaneously be both a header and a list, despite being possible to represent in the Delta format.
## Changes
When you register a listener for Quill's [`text-change`](/docs/api/#text-change) event, one of the arguments you will get is a Delta describing what changed. In addition to `insert` operations, this Delta might also have `delete` or `retain` operations.
### Delete
The `delete` operation instructs exactly what it implies: delete the next number of characters.
```javascript
{
ops: [
{ delete: 10 } // Delete the next 10 characters
]
}
```
Since `delete` operations do not include _what_ was deleted, a Delta is not reversible.
### Retain
A `retain` operation simply means keep the next number of characters, without modification. If `attributes` is specified, it still means keep those characters, but apply the formatting specified by the `attributes` object. A `null` value for an attributes key is used to specify format removal.
Starting with the above "Gandalf the Grey" example:
```javascript
// {
// ops: [
// { insert: 'Gandalf', attributes: { bold: true } },
// { insert: ' the ' },
// { insert: 'Grey', attributes: { color: '#cccccc' } }
// ]
// }
{
ops: [
// Unbold and italicize "Gandalf"
{ retain: 7, attributes: { bold: null, italic: true } },
// Keep " the " as is
{ retain: 5 },
// Insert "White" formatted with color #fff
{ insert: 'White', attributes: { color: '#fff' } },
// Delete "Grey"
{ delete: 4 }
]
}
```
Note that a Delta's instructions always starts at the beginning of the document. And because of plain `retain` operations, we never need to specify an index for a `delete` or `insert` operation.
### Playground
Play around with Quill and take a look at how its content and changes look. Open your developer console for another view into the Deltas.
<SandpackWithQuillTemplate
preferPreview
afterEditor={`
<pre id="playground" style="font-size: 12px">
</pre>
`}
files={{
'index.js': `
const quill = new Quill('#editor', { theme: 'snow' });
quill.on(Quill.events.TEXT_CHANGE, update);
const playground = document.querySelector('#playground');
update();
function formatDelta(delta) {
return \`<div>\${JSON.stringify(delta.ops, null, 2)}</div>\`;
}
function update(delta) {
const contents = quill.getContents();
let html = \`<h3>contents</h3>\${formatDelta(contents)}\`
if (delta) {
html = \`\${html}<h3>change</h3>\${formatDelta(delta)}\`;
}
playground.innerHTML = html;
}
`
}}
/>

View File

@@ -7,6 +7,7 @@ const openaiOptions: ClientOptions = {
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL,
maxRetries: parseInt(process.env.OPENAI_MAX_RETRIES as string) ?? 3,
dangerouslyAllowBrowser: true,
}
@Module({

View File

@@ -1,6 +1,11 @@
import { Injectable } from '@nestjs/common'
import { Injectable, Logger } from '@nestjs/common'
import { OpenAI } from 'openai'
import { DocumentDelta } from 'src/Document/document.type'
import Delta from 'quill-delta'
import { z } from 'zod'
import { zodResponseFormat } from 'openai/helpers/zod'
import { readFileSync } from 'fs'
const DELTA_INSTRUCTIONS = readFileSync('./src/OpenAI/Instructions/delta.mdx.txt', 'utf8')
@Injectable()
export class OpenaiService {
@@ -19,16 +24,173 @@ export class OpenaiService {
return response.choices[0].message.content
}
async documentSuggestEditDelta(documentDelta: DocumentDelta): Promise<DocumentDelta> {
const prompt = `
give me suggestion for edit document delta to EPESS and replace {{ documentDelta }} with ${documentDelta}
`
async documentSuggestEditDelta(documentDelta: Delta): Promise<Delta> {
// Redefine the schema for Delta.Op with more detailed validations
const deltaOpSchema = z
.object({
insert: z.string().optional(),
delete: z.number().optional(),
retain: z.number().optional(),
attributes: z
.object({
bold: z.boolean().optional(),
italic: z.boolean().optional(),
color: z.string().optional(),
link: z.string().optional(),
header: z.number().optional(),
// Add any other attributes that may be required here
})
.optional(),
})
.strict()
const response = await this.openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
// Define the overall schema for Delta operations
const schema = z.object({
ops: z.array(deltaOpSchema),
})
return response.choices[0].message.content as unknown as DocumentDelta
const systemPrompt = `
System: You are an assistant tasked with editing document content in QuillJS Delta format. You will receive a document and editing instructions. Your goal is to modify the document while maintaining the exact **language**, **tone**, **structure**, and **intent** of the original content. Every modification must be consistent with the original style. Please follow the instructions meticulously and ensure all operations are precisely represented in Delta format.
1. **Document Content (Delta Format):**
- The document content is provided in QuillJS Delta format. This is the **original** document content. Do not alter or change the language or tone of the original content unless specifically instructed.
---BEGIN---
(Insert the original document content in Delta format here.)
---END---
2. **Editing Instructions (Delta Format):**
- Below are the instructions for editing the document. Follow these instructions strictly and ensure that changes are applied precisely as requested. Do not introduce new meanings or alter the context of the original document.
---BEGIN---
(Insert detailed instructions here, specifying what text should be modified, added, deleted, or reformatted.)
---END---
3. **Editing Requirements:**
- **Language Consistency**: The document's language must remain consistent throughout. Do **not** introduce new phrasing, terms, or language that deviates from the original document's style or tone.
- **Preserve the Intent**: Ensure that the intended meaning of the document is maintained. If the instructions suggest changes, they must fit within the overall context and tone of the original.
- **Formatting and Structure**: Respect the original formatting and structural layout. Any modifications should adhere to the same format as the source document.
- **Modification Representation**: All changes should be accurately reflected in **Delta format**, which includes:
- **Insert**: For adding new text or content (e.g., images, links).
- **Delete**: For removing content.
- **Retain**: For keeping content but potentially modifying formatting or attributes.
4. **Web Browsing and Reference Suggestions:**
- If applicable, suggest **web references** that are directly relevant to the content. If web browsing is required, ensure the reference links are **reliable**, **valid**, and fit seamlessly within the document's language.
- When suggesting external links, make sure they are:
- **Relevant** to the document's context.
- **Formatted correctly** with proper citations.
5. **Delta Operations (Insert, Delete, Retain):**
- Ensure that all modifications are represented by the appropriate **Delta operations**:
- **Insert**: Add new content (text, images, etc.).
- **Delete**: Remove content.
- **Retain**: Keep content with no change, or only adjust its attributes.
- All modifications should be **accurately** expressed using these operations.
6. **Handling Non-Text Content (Embeds):**
- If there are changes to non-text elements (such as images, links, or videos), ensure they are added correctly using the **insert** operation with appropriate attributes (e.g., \`link\`, \`image\`).
- Example:
\`\`\`json
{
"ops": [
{
"insert": { "image": "https://example.com/image.png" },
"attributes": { "link": "https://example.com" }
}
]
}
\`\`\`
7. **Line and Paragraph Formatting:**
- If changes involve formatting at the line or paragraph level (e.g., headings, lists, indentation), apply the appropriate **attributes**:
- Example for adding a heading:
\`\`\`json
{
"ops": [
{ "insert": "New Heading" },
{ "insert": "\\n", "attributes": { "header": 2 } }
]
}
\`\`\`
8. **Character Count and Delta Operations:**
- Ensure that **Delta operations** correctly represent the changes to text length. Track the **character count** and ensure the Delta format reflects both the original and modified content accurately.
9. **Final Output:**
- The **final output** must be a valid QuillJS Delta format document that:
- Contains the necessary Delta operations (insert, delete, retain).
- Reflects all modifications clearly and precisely, without altering the documents original tone, intent, or structure.
10. **Additional Instructions for Handling Complex Edits:**
- If the document requires complex edits (e.g., restructuring, replacing long sections of text), break the edits into smaller steps and ensure each step follows the same language and tone.
`
const userPrompt = `
User: I need you to edit the following document in QuillJS Delta format according to the instructions below.
1. **Document Content (Delta Format):**
- Here is the document content in QuillJS Delta format. This is the **original** content of the document, and it must be preserved in **language, tone, and structure** unless specifically instructed otherwise.
---BEGIN---
${JSON.stringify(documentDelta)}
---END---
2. **Editing Instructions (Delta Format):**
- Below are the detailed instructions for editing the content. Follow these instructions exactly as provided, ensuring that any changes made are in line with the original language and tone of the document.
---BEGIN---
${DELTA_INSTRUCTIONS}
---END---
3. **Requirements:**
- **Language and Tone**: Do not deviate from the original language or tone. Any changes should be phrased in the same style and maintain the same level of formality, diction, and style.
- **Preserve Intent**: Ensure that all edits preserve the original intent and meaning of the document. Avoid any rephrasing or changes that alter the message.
- **Accurate Delta Representation**: Ensure all changes are accurately reflected in **Delta format**:
- **Insert**: For new content.
- **Delete**: For removed content.
- **Retain**: For unchanged content with potential formatting changes.
4. **Web Browsing and Reference Suggestions:**
- If needed, suggest **web references** that are relevant to the document's context. Only insert valid URLs with descriptions that complement the document's language and tone.
5. **Output:**
- Provide the final **Delta format output** that accurately reflects all changes, including inserts, deletes, and retains, while maintaining consistency in language and tone.
6. **Delta Format Schema:**
- Ensure the Delta format adheres to the following structure:
- **Insert**: For adding new content (text, links, images, etc.).
- **Delete**: For removing content.
- **Retain**: For keeping content, but possibly modifying formatting or attributes.
7. **Handling Non-Text Embeds:**
- For any non-text content, such as **images** or **videos**, use the appropriate **insert** operation with attributes. Ensure that any media links are formatted correctly and are relevant to the documents content.
`
Logger.log(userPrompt, 'userPrompt')
try {
const response = await this.openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
response_format: zodResponseFormat(schema, 'Delta'),
})
const result = JSON.parse(response.choices[0].message.content ?? '') as Delta
// Validate that the result matches the expected structure
schema.parse(result)
Logger.log(result, 'result')
return result
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
} catch (error: any) {
Logger.error(`Error in Delta processing: ${error.message}`, 'OpenaiService')
throw new Error('Failed to process Delta changes.')
}
}
}