Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
"uuidv4": "^6.2.13",
"youtube-transcript": "^1.1.0",
"zod": "^3.22.4"
"docxtemplater": "^3.37.9",
"docxtemplater-image-module-free": "^1.1.1",
"pizzip": "^3.1.4"
},
"devDependencies": {
"@commitlint/cli": "^19.0.3",
Expand Down
29 changes: 28 additions & 1 deletion src/routes/wordGenerator/wordGeneratorModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export const WordGeneratorResponseSchema = z.object({
filepath: z.string().openapi({
description: 'The file path where the generated Word document is saved.',
}),
downloadUrl: z.string().openapi({
description: 'The URL to download the generated document',
}),
});

// Define Cell Schema
Expand Down Expand Up @@ -64,7 +67,14 @@ const SectionSchema = z.object({
}),
});

// Request Body Schema
// ADDED: Template selection schema
const TemplateSelectionSchema = z.object({
templateId: z.string().optional().openapi({
description: 'ID of the company template to use. If not provided, the default template will be used.',
}),
});

// Request Body Schema - MODIFIED to include template selection
export const WordGeneratorRequestBodySchema = z.object({
title: z.string().openapi({
description: 'Title of the document.',
Expand All @@ -88,6 +98,10 @@ export const WordGeneratorRequestBodySchema = z.object({
sections: z.array(SectionSchema).openapi({
description: 'Sections of the document, which may include sub-sections.',
}),
// ADDED: Template selection
template: TemplateSelectionSchema.optional().openapi({
description: 'Template settings for the document',
}),
wordConfig: z
.object({
fontSize: z.number().default(12).openapi({
Expand Down Expand Up @@ -136,3 +150,16 @@ export const WordGeneratorRequestBodySchema = z.object({
});

export type WordGeneratorRequestBody = z.infer<typeof WordGeneratorRequestBodySchema>;

// ADDED: API to get available templates
export const GetAvailableTemplatesResponseSchema = z.object({
templates: z.array(
z.object({
id: z.string(),
name: z.string(),
description: z.string(),
})
),
});

export type GetAvailableTemplatesResponse = z.infer<typeof GetAvailableTemplatesResponseSchema>;
138 changes: 138 additions & 0 deletions src/routes/wordGenerator/wordGeneratorModel_org.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
import { z } from 'zod';

extendZodWithOpenApi(z);

// Define Word Generator Response Schema
export type WordGeneratorResponse = z.infer<typeof WordGeneratorResponseSchema>;
export const WordGeneratorResponseSchema = z.object({
filepath: z.string().openapi({
description: 'The file path where the generated Word document is saved.',
}),
});

// Define Cell Schema
const CellSchema = z.object({
text: z.string().optional().openapi({
description: 'Text content within a cell.',
}),
});

// Define Row Schema
const RowSchema = z.object({
cells: z.array(CellSchema).optional().openapi({
description: 'Array of cells within a row.',
}),
});

// Define Content Schema
const ContentSchema = z.object({
type: z.enum(['paragraph', 'listing', 'table', 'pageBreak', 'emptyLine']).openapi({
description: 'Type of the content item.',
}),
text: z.string().optional().openapi({
description: 'Text content for paragraphs or listings.',
}),
items: z.array(z.string()).optional().openapi({
description: 'Items in a list for listing type content.',
}),
headers: z.array(z.string()).optional().openapi({
description: 'Headers for table content.',
}),
rows: z.array(RowSchema).optional().openapi({
description: 'Rows for table content.',
}),
});

// Define the base schema for a section
const SectionSchema = z.object({
sectionId: z.string().openapi({
description: 'A unique identifier for the section.',
}),
heading: z.string().optional().openapi({
description: 'Heading of the section.',
}),
headingLevel: z.number().int().min(1).optional().openapi({
description: 'Level of the heading (e.g., 1 for main heading, 2 for subheading).',
}),
parentSectionId: z.string().optional().openapi({
description:
'The unique identifier of the parent section, if this section is a child of another. Leave empty if this section has no parent.',
}),
content: z.array(ContentSchema).optional().openapi({
description: 'Content contained within the section, including paragraphs, tables, etc.',
}),
});

// Request Body Schema
export const WordGeneratorRequestBodySchema = z.object({
title: z.string().openapi({
description: 'Title of the document.',
}),
header: z.object({
text: z.string().openapi({
description: 'Text content for the header.',
}),
alignment: z.enum(['left', 'center', 'right']).default('left').openapi({
description: 'Alignment of the header text.',
}),
}),
footer: z.object({
text: z.string().openapi({
description: 'Text content for the footer.',
}),
alignment: z.enum(['left', 'center', 'right']).default('left').openapi({
description: 'Alignment of the footer text.',
}),
}),
sections: z.array(SectionSchema).openapi({
description: 'Sections of the document, which may include sub-sections.',
}),
wordConfig: z
.object({
fontSize: z.number().default(12).openapi({
description: 'Font size for the slides, default is 12 pt.',
}),
lineHeight: z.enum(['1', '1.15', '1.25', '1.5', '2']).default('1').openapi({
description: 'Line height for text content.',
}),
fontFamily: z
.enum(['Arial', 'Calibri', 'Times New Roman', 'Courier New', 'Verdana', 'Tahoma', 'Georgia', 'Comic Sans MS'])
.default('Arial')
.openapi({
description: 'Font family for the slides, default is Arial.',
}),
showPageNumber: z.boolean().default(false).openapi({
description: 'Option to display page numbers in the document.',
}),
showTableOfContent: z.boolean().default(false).openapi({
description: 'Option to display a table of contents.',
}),
showNumberingInHeader: z.boolean().default(false).openapi({
description: 'Option to display numbering in the header.',
}),
numberingReference: z
.enum([
'1.1.1.1 (Decimal)',
'I.1.a.i (Roman -> Decimal > Lower Letter -> Lower Roman)',
'I.A.1.a (Roman -> Upper Letter -> Decimal -> Lower Letter)',
'1)a)i)(i) (Decimal -> Lower Letter -> Lower Roman -> Lower Roman with Parentheses)',
'A.1.a.i (Upper Letter -> Decimal -> Lower Letter -> Lower Roman)',
])
.default('1.1.1.1 (Decimal)')
.openapi({
description: 'Set numbering hierarchy format for the document.',
}),
pageOrientation: z.enum(['portrait', 'landscape']).default('portrait').openapi({
description: 'Set the page orientation for the document.',
}),
margins: z.enum(['normal', 'narrow', 'moderate', 'wide', 'mirrored']).default('normal').openapi({
description: 'Set page margins for the document.',
}),
})
.openapi({
description: 'Word configuration settings for generating the document.',
}),
});

export type WordGeneratorRequestBody = z.infer<typeof WordGeneratorRequestBodySchema>;
Loading