├── .gitignore ├── GenerateBarcode ├── .gitignore ├── package-lock.json ├── package.json ├── src │ ├── api.ts │ ├── app.ts │ └── shims.d.ts └── tsconfig.json ├── GenerateQRCode ├── .gitignore ├── package-lock.json ├── package.json ├── src │ ├── api.ts │ ├── app.ts │ └── shims.d.ts └── tsconfig.json ├── TTA-endpoint ├── .gitignore ├── package-lock.json ├── package.json ├── src │ └── index.ts └── tsconfig.json ├── dist ├── api.js ├── app.js └── pdf.worker.mjs ├── images └── Operations.png ├── installationhook ├── .gitignore ├── package-lock.json ├── package.json ├── src │ └── index.ts ├── tsconfig.json └── yarn.lock ├── license ├── ocr ├── OCR-interface │ ├── .gitignore │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── interface.vue │ │ ├── languages.ts │ │ ├── ocredrag.vue │ │ ├── renderOCRResponse.vue │ │ └── shims.d.ts │ ├── tsconfig.json │ └── yarn.lock └── OCR-operator │ ├── api.ts │ ├── app.ts │ ├── languages.ts │ └── shims.d.ts ├── package.json ├── pdf ├── GeneratePDF │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── api.ts │ │ ├── app.ts │ │ └── shims.d.ts │ └── tsconfig.json ├── GeneratePDFFromTemplateInterface │ ├── .gitignore │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── interface.vue │ │ └── shims.d.ts │ └── tsconfig.json ├── GeneratePDFGenerateFromTemplate │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── api.ts │ │ ├── app.ts │ │ └── shims.d.ts │ └── tsconfig.json └── PDFTemplateSelector │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── index.ts │ ├── interface.vue │ └── shims.d.ts │ └── tsconfig.json ├── readme.md ├── settingsmodule ├── .gitignore ├── package-lock.json ├── package.json ├── src │ ├── TTAnav.vue │ ├── components │ │ ├── dateTimePicker.vue │ │ └── displayFlowLogs.vue │ ├── constants.ts │ ├── index.ts │ ├── pages │ │ ├── flowLogsExplorer.vue │ │ ├── settings.vue │ │ ├── templates.vue │ │ └── templates │ │ │ └── explainPreviewMode.vue │ └── shims.d.ts └── tsconfig.json ├── test.json ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /GenerateBarcode/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /GenerateBarcode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-GenerateBarcode", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-operation" 8 | ], 9 | "directus:extension": { 10 | "type": "operation", 11 | "path": { 12 | "app": "../../extensions/operations/GenerateBarcode/app.js", 13 | "api": "../../extensions/operations/GenerateBarcode/api.js" 14 | }, 15 | "source": { 16 | "app": "src/app.ts", 17 | "api": "src/api.ts" 18 | }, 19 | "host": "^9.22.1" 20 | }, 21 | "scripts": { 22 | "build": "directus-extension build", 23 | "dev": "directus-extension build -w --no-minify" 24 | }, 25 | "devDependencies": { 26 | "@directus/extensions-sdk": "9.22.1", 27 | "@types/node": "^18.11.18", 28 | "typescript": "^4.9.4", 29 | "vue": "^3.2.45" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GenerateBarcode/src/api.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApi } from "@directus/extensions-sdk"; 2 | 3 | type Options = { 4 | "RapidAPI token": string; 5 | barcodeContent: string; 6 | includetext: boolean; 7 | barcodeType: string; 8 | scale: number; 9 | height: number; 10 | }; 11 | 12 | export default defineOperationApi({ 13 | id: "ttabarcode", 14 | handler: async (context) => { 15 | return await (globalThis as any).TTA.generateBarCode(context); 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /GenerateBarcode/src/app.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApp } from "@directus/extensions-sdk"; 2 | const types = [ 3 | "auspost", 4 | "azteccode", 5 | "azteccodecompact", 6 | "aztecrune", 7 | "bc412", 8 | "channelcode", 9 | "codablockf", 10 | "code11", 11 | "code128", 12 | "code16k", 13 | "code2of5", 14 | "code32", 15 | "code39", 16 | "code39ext", 17 | "code49", 18 | "code93", 19 | "code93ext", 20 | "codeone", 21 | "coop2of5", 22 | "daft", 23 | "databarexpanded", 24 | "databarexpandedcomposite", 25 | "databarexpandedstacked", 26 | "databarexpandedstackedcomposite", 27 | "databarlimited", 28 | "databarlimitedcomposite", 29 | "databaromni", 30 | "databaromnicomposite", 31 | "databarstacked", 32 | "databarstackedcomposite", 33 | "databarstackedomni", 34 | "databarstackedomnicomposite", 35 | "databartruncated", 36 | "databartruncatedcomposite", 37 | "datalogic2of5", 38 | "datamatrix", 39 | "datamatrixrectangular", 40 | "datamatrixrectangularextension", 41 | "dotcode", 42 | "ean13", 43 | "ean13composite", 44 | "ean14", 45 | "ean2", 46 | "ean5", 47 | "ean8", 48 | "ean8composite", 49 | "flattermarken", 50 | "gs1-128", 51 | "gs1-128composite", 52 | "gs1-cc", 53 | "gs1datamatrix", 54 | "gs1datamatrixrectangular", 55 | "gs1dldatamatrix", 56 | "gs1dlqrcode", 57 | "gs1dotcode", 58 | "gs1northamericancoupon", 59 | "gs1qrcode", 60 | "hanxin", 61 | "hibcazteccode", 62 | "hibccodablockf", 63 | "hibccode128", 64 | "hibccode39", 65 | "hibcdatamatrix", 66 | "hibcdatamatrixrectangular", 67 | "hibcmicropdf417", 68 | "hibcpdf417", 69 | "hibcqrcode", 70 | "iata2of5", 71 | "identcode", 72 | "industrial2of5", 73 | "interleaved2of5", 74 | "isbn", 75 | "ismn", 76 | "issn", 77 | "itf14", 78 | "japanpost", 79 | "kix", 80 | "leitcode", 81 | "mailmark", 82 | "mands", 83 | "matrix2of5", 84 | "maxicode", 85 | "micropdf417", 86 | "microqrcode", 87 | "msi", 88 | "onecode", 89 | "pdf417", 90 | "pdf417compact", 91 | "pharmacode", 92 | "pharmacode2", 93 | "planet", 94 | "plessey", 95 | "posicode", 96 | "postnet", 97 | "pzn", 98 | "qrcode", 99 | "rationalizedCodabar", 100 | "raw", 101 | "rectangularmicroqrcode", 102 | "royalmail", 103 | "sscc18", 104 | "swissqrcode", 105 | "symbol", 106 | "telepen", 107 | "telepennumeric", 108 | "ultracode", 109 | "upca", 110 | "upcacomposite", 111 | "upce", 112 | "upcecomposite", 113 | ]; 114 | 115 | export default defineOperationApp({ 116 | id: "ttabarcode", 117 | name: "TTA generate barcode", 118 | icon: "barcode", 119 | description: "Generate a barcode trough Text to anything!", 120 | overview: ({ barcodeContent }) => [ 121 | { 122 | label: "barcode content", 123 | text: barcodeContent, 124 | }, 125 | ], 126 | options: [ 127 | { 128 | field: "barcodeContent", 129 | name: "content", 130 | type: "string", 131 | meta: { 132 | width: "full", 133 | interface: "input", 134 | }, 135 | }, 136 | { 137 | field: "barcodeType", 138 | name: "type", 139 | type: "dropdown", 140 | meta: { 141 | interface: "select-dropdown", 142 | options: { 143 | choices: types.map((e) => ({ text: e, value: e })), 144 | }, 145 | }, 146 | }, 147 | { 148 | field: "scale", 149 | name: "scale", 150 | type: "number", 151 | meta: { 152 | width: "full", 153 | interface: "input", 154 | }, 155 | }, 156 | { 157 | field: "height", 158 | name: "height", 159 | type: "number", 160 | meta: { 161 | width: "full", 162 | interface: "input", 163 | }, 164 | }, 165 | { 166 | field: "includetext", 167 | name: "include text", 168 | type: "boolean", 169 | meta: { 170 | width: "full", 171 | interface: "boolean", 172 | }, 173 | }, 174 | ], 175 | }); 176 | -------------------------------------------------------------------------------- /GenerateBarcode/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /GenerateBarcode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /GenerateQRCode/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /GenerateQRCode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-GenerateQRCode", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-operation" 8 | ], 9 | "directus:extension": { 10 | "type": "operation", 11 | "path": { 12 | "app": "../../extensions/operations/GenerateQRCode/app.js", 13 | "api": "../../extensions/operations/GenerateQRCode/api.js" 14 | }, 15 | "source": { 16 | "app": "src/app.ts", 17 | "api": "src/api.ts" 18 | }, 19 | "host": "^9.22.1" 20 | }, 21 | "scripts": { 22 | "build": "directus-extension build", 23 | "dev": "directus-extension build -w --no-minify" 24 | }, 25 | "devDependencies": { 26 | "@directus/extensions-sdk": "9.22.1", 27 | "@types/node": "^18.11.18", 28 | "typescript": "^4.9.4", 29 | "vue": "^3.2.45" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GenerateQRCode/src/api.ts: -------------------------------------------------------------------------------- 1 | import { toArray } from "@directus/shared/utils"; 2 | import { defineOperationApi } from "@directus/extensions-sdk"; 3 | import axios from "axios"; 4 | 5 | type Options = { 6 | "RapidAPI token": string; 7 | qrcodeContent: string; 8 | }; 9 | 10 | export default defineOperationApi({ 11 | id: "ttaqrcode", 12 | handler: async (context) => { 13 | return await (globalThis as any).TTA.generateQRCode(context); 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /GenerateQRCode/src/app.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApp } from "@directus/extensions-sdk"; 2 | 3 | export default defineOperationApp({ 4 | id: "ttaqrcode", 5 | name: "TTA generate QRcode", 6 | icon: "qr_code", 7 | description: "Generate a QRcode trough Text to anything!", 8 | overview: ({ content }) => [ 9 | { 10 | label: "QRCode content", 11 | text: content, 12 | }, 13 | ], 14 | options: [ 15 | { 16 | field: "content", 17 | name: "QRCode content", 18 | type: "string", 19 | meta: { 20 | width: "full", 21 | interface: "input", 22 | }, 23 | }, 24 | { 25 | field: "lightColor", 26 | name: "Light color", 27 | type: "string", 28 | meta: { 29 | width: "full", 30 | interface: "input", 31 | }, 32 | }, 33 | { 34 | field: "darkColor", 35 | name: "Dark color", 36 | type: "string", 37 | meta: { 38 | width: "full", 39 | interface: "input", 40 | }, 41 | }, 42 | { 43 | field: "margin", 44 | name: "Margin", 45 | type: "integer", 46 | meta: { 47 | width: "half", 48 | interface: "input", 49 | }, 50 | }, 51 | { 52 | field: "width", 53 | name: "Width", 54 | type: "integer", 55 | meta: { 56 | width: "half", 57 | interface: "input", 58 | }, 59 | }, 60 | ], 61 | }); 62 | -------------------------------------------------------------------------------- /GenerateQRCode/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /GenerateQRCode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /TTA-endpoint/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /TTA-endpoint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tta-endpoint", 3 | "description": "Please enter a description for your extension", 4 | "icon": "extension", 5 | "version": "1.0.0", 6 | "keywords": [ 7 | "directus", 8 | "directus-extension", 9 | "directus-extension-endpoint" 10 | ], 11 | "type": "module", 12 | "files": [ 13 | "dist" 14 | ], 15 | "directus:extension": { 16 | "type": "endpoint", 17 | "path": "dist/index.js", 18 | "source": "src/index.ts", 19 | "host": "^10.10.0" 20 | }, 21 | "scripts": { 22 | "build": "directus-extension build", 23 | "dev": "directus-extension build -w --no-minify", 24 | "link": "directus-extension link", 25 | "validate": "directus-extension validate" 26 | }, 27 | "devDependencies": { 28 | "@directus/extensions-sdk": "13.1.0", 29 | "@types/node": "^22.15.3", 30 | "typescript": "^5.8.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TTA-endpoint/src/index.ts: -------------------------------------------------------------------------------- 1 | import Busboy from "busboy"; 2 | import fs from "node:fs"; 3 | import axios from "axios"; 4 | import express from "express"; 5 | 6 | // File processing middleware 7 | const fileParser = (req, res, next) => { 8 | if (!req.is("multipart/form-data")) { 9 | return next(); 10 | } 11 | 12 | const busboy = Busboy({ headers: req.headers }); 13 | req.fileData = {}; // Store file data 14 | req.fields = {}; // Store form fields 15 | 16 | // Handle file parts 17 | busboy.on("file", (fieldname, file, { filename, encoding, mimeType }) => { 18 | const chunks = []; 19 | 20 | file.on("data", (data) => { 21 | chunks.push(data); 22 | }); 23 | 24 | file.on("end", () => { 25 | const buffer = Buffer.concat(chunks); 26 | // Place file on req.file 27 | req.file = { 28 | fieldname, 29 | buffer, 30 | filename, 31 | encoding, 32 | mimeType, 33 | }; 34 | }); 35 | }); 36 | 37 | // Handle non-file fields 38 | busboy.on("field", (fieldname, value) => { 39 | req.fields[fieldname] = value; 40 | }); 41 | 42 | // When all parts have been processed 43 | busboy.on("finish", () => { 44 | next(); 45 | }); 46 | 47 | busboy.on("error", (err) => { 48 | console.error("Busboy error:", err); 49 | res.status(400).json({ 50 | success: false, 51 | error: "Error parsing form data", 52 | details: err.message, 53 | }); 54 | }); 55 | 56 | req.pipe(busboy); 57 | }; 58 | 59 | export default { 60 | id: "tta", 61 | handler: (router) => { 62 | router.use((req, res, next) => { 63 | if (req.accountability?.user == null) { 64 | res.status(403); 65 | return res.send(`You don't have permission to access this.`); 66 | } 67 | 68 | next(); 69 | }); 70 | 71 | router.get("/pdf.worker.mjs", (req, res) => { 72 | console.log(__dirname); 73 | return res.sendFile(__dirname + "/pdf.worker.mjs"); 74 | }); 75 | 76 | router.post("/pdf", express.json(), async (req, res) => { 77 | const { 78 | status, 79 | headers, 80 | data: bodyStream, 81 | } = await axios 82 | .post( 83 | "https://text-to-anything.p.rapidapi.com/generatePDF/" + 84 | (req.query?.preview ? "preview" : ""), 85 | req.body, 86 | { 87 | headers: { 88 | "X-RapidAPI-Key": await globalThis.TTA._getRapidAPIKey(), 89 | }, 90 | responseType: "stream", 91 | decompress: false, 92 | } 93 | ) 94 | .catch(globalThis.TTA._handleRapidAPIError); 95 | 96 | res.status(status); 97 | res.set(headers); 98 | 99 | bodyStream.pipe(res); 100 | }); 101 | 102 | router.post("/ocr", fileParser, async (req, res) => { 103 | if (!req.file) { 104 | res.status(400); 105 | return res.send(`You did not provide a file.`); 106 | } 107 | const { language } = req.query; 108 | 109 | if (!req.file) { 110 | res.status(400); 111 | return res.send(`You did not provide a language.`); 112 | } 113 | 114 | const response = await globalThis.TTA.OCRbasedOnFileBuffer( 115 | req.file.buffer, 116 | req.file.filename, 117 | language, 118 | "blocks" 119 | ); 120 | res.json(response); 121 | }); 122 | }, 123 | }; 124 | -------------------------------------------------------------------------------- /TTA-endpoint/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /images/Operations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Attacler/TextToAnything-Directus/9933274d92d930a623ad465cd377e26001dd2716/images/Operations.png -------------------------------------------------------------------------------- /installationhook/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /installationhook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-installationhook", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-hook" 8 | ], 9 | "directus:extension": { 10 | "type": "hook", 11 | "path": "dist/index.js", 12 | "source": "src/index.ts", 13 | "host": "^9.22.1" 14 | }, 15 | "scripts": { 16 | "build": "directus-extension build", 17 | "dev": "directus-extension build -w --no-minify" 18 | }, 19 | "devDependencies": { 20 | "@directus/extensions-sdk": "9.22.1", 21 | "@types/node": "^20.9.2", 22 | "typescript": "^5.2.2" 23 | }, 24 | "dependencies": { 25 | "axios": "^1.9.0", 26 | "form-data": "^4.0.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /installationhook/src/index.ts: -------------------------------------------------------------------------------- 1 | import { toArray } from "@directus/shared/utils"; 2 | import { defineHook } from "@directus/extensions-sdk"; 3 | import { Liquid } from "liquidjs"; 4 | import axios from "axios"; 5 | import FormData from "form-data"; 6 | import { createReadStream } from "node:fs"; 7 | 8 | const engine = new Liquid(); 9 | 10 | export default defineHook(({}, { services, getSchema, logger, env }) => { 11 | getSchema().then(async (schema) => { 12 | const collectionService = new services.CollectionsService({ schema }); 13 | 14 | const collectionExists = 15 | (schema.collections || {})["TTA_htmltemplates"] != null; 16 | 17 | if (!collectionExists) { 18 | await collectionService.createOne({ 19 | collection: "TTA_htmltemplates", 20 | meta: { 21 | hidden: true, 22 | icon: "code", 23 | singleton: false, 24 | }, 25 | fields: [ 26 | { 27 | field: "id", 28 | type: "integer", 29 | meta: { 30 | hidden: true, 31 | interface: "input", 32 | readonly: true, 33 | }, 34 | schema: { 35 | is_primary_key: true, 36 | has_auto_increment: true, 37 | }, 38 | }, 39 | ], 40 | schema: {}, 41 | }); 42 | 43 | schema = await getSchema(); 44 | } 45 | const fieldsService = new services.FieldsService({ schema }); 46 | 47 | const { fields } = schema.collections.TTA_htmltemplates!; 48 | 49 | if (fields.description == null) await addField("description", "text"); 50 | if (fields.collection == null) await addField("collection", "string"); 51 | if (fields.name == null) await addField("name", "text"); 52 | if (fields.header == null) await addField("header", "text"); 53 | if (fields.template == null) await addField("template", "text"); 54 | if (fields.footer == null) await addField("footer", "text"); 55 | if (fields.format == null) await addField("format", "string"); 56 | if (fields.orientation == null) await addField("orientation", "string"); 57 | if (fields.input_type == null) await addField("input_type", "string"); 58 | if (fields.input_flow == null) await addField("input_flow", "string"); 59 | if (fields.input_flow_body == null) 60 | await addField("input_flow_body", "text"); 61 | if (fields.input_fixed == null) await addField("input_fixed", "text"); 62 | 63 | if (schema.collections.directus_settings?.fields.TTA_KEY == null) { 64 | await addField( 65 | "TTA_KEY", 66 | "string", 67 | { hidden: true }, 68 | "directus_settings" 69 | ); 70 | } 71 | 72 | (globalThis as any).TTA = { 73 | async generateBarCode(context: any) { 74 | const fileSerice = new services.FilesService({ 75 | schema: await getSchema(), 76 | }); 77 | 78 | const download = await axios 79 | .get("https://text-to-anything.p.rapidapi.com/generateBarcode", { 80 | params: { 81 | content: context.barcodeContent, 82 | type: context.barcodeType, 83 | scale: context.scale, 84 | height: context.height, 85 | includetext: context.includetext, 86 | }, 87 | headers: { 88 | "X-RapidAPI-Key": await getRapidAPIKey(), 89 | }, 90 | responseType: "stream", 91 | }) 92 | .catch(handleRapidAPIError); 93 | 94 | return await fileSerice.uploadOne(download.data, { 95 | filename_download: "barcode-" + context.barcodeContent + ".gif", 96 | type: download.headers["content-type"], 97 | storage: toArray(env.STORAGE_LOCATIONS)[0], 98 | }); 99 | }, 100 | async generatePDF(context: any) { 101 | if (context.pdfoptions?.html == null) { 102 | throw new Error("No HTML found!"); 103 | } 104 | 105 | if (Object.keys(context.templatevariables || {}).length > 0) { 106 | const header = engine.parse(context.pdfoptions.header || ""); 107 | const tpl = engine.parse(context.pdfoptions.html); 108 | const footer = engine.parse(context.pdfoptions.footer || ""); 109 | context.pdfoptions.header = await engine.render( 110 | header, 111 | context.templatevariables 112 | ); 113 | context.pdfoptions.html = await engine.render( 114 | tpl, 115 | context.templatevariables 116 | ); 117 | context.pdfoptions.footer = await engine.render( 118 | footer, 119 | context.templatevariables 120 | ); 121 | } 122 | const fileSerice = new services.FilesService({ 123 | schema: await getSchema(), 124 | }); 125 | 126 | const download = await axios 127 | .post( 128 | "https://text-to-anything.p.rapidapi.com/generatePDF" + 129 | (context.preview ? "/preview" : "/"), 130 | context.pdfoptions, 131 | { 132 | headers: { 133 | "X-RapidAPI-Key": await getRapidAPIKey(), 134 | }, 135 | responseType: "stream", 136 | } 137 | ) 138 | .catch(handleRapidAPIError); 139 | 140 | return await fileSerice.uploadOne(download.data, { 141 | filename_download: context.filename || new Date().getTime() + ".pdf", 142 | type: download.headers["content-type"], 143 | storage: toArray(env.STORAGE_LOCATIONS)[0], 144 | }); 145 | }, 146 | async generatePDFFromTemplate(context: any) { 147 | const templateService = new services.ItemsService("TTA_htmltemplates", { 148 | schema: await getSchema(), 149 | }); 150 | const template = await templateService.readOne(context.template); 151 | 152 | return await (globalThis as any).TTA.generatePDF({ 153 | ...context, 154 | pdfoptions: { 155 | ...template, 156 | html: template.template, 157 | landscape: template.orientation == "landscape", 158 | }, 159 | }); 160 | }, 161 | async generateQRCode(context: any) { 162 | const fileSerice = new services.FilesService({ 163 | schema: await getSchema(), 164 | }); 165 | 166 | const download = await axios 167 | .get("https://text-to-anything.p.rapidapi.com/generateQR", { 168 | params: context, 169 | headers: { 170 | "X-RapidAPI-Key": context["RapidAPI token"], 171 | }, 172 | responseType: "stream", 173 | }) 174 | .catch(handleRapidAPIError); 175 | 176 | return await fileSerice.uploadOne(download.data, { 177 | filename_download: "qrcode-" + context.qrcodeContent + ".png", 178 | type: download.headers["content-type"], 179 | storage: toArray(env.STORAGE_LOCATIONS)[0], 180 | }); 181 | }, 182 | async OCRBasedOnAsset(fileID: string, language: string, mode: string) { 183 | const assetsService = new services.AssetsService({ 184 | schema: await getSchema(), 185 | }); 186 | 187 | const { stream, file } = await assetsService.getAsset(fileID); 188 | 189 | const chunks = []; 190 | 191 | for await (const chunk of stream) { 192 | chunks.push(chunk); 193 | } 194 | 195 | const result = await globalThis.TTA.OCRbasedOnFileBuffer( 196 | Buffer.concat(chunks), 197 | file.filename_download, 198 | language, 199 | mode 200 | ); 201 | 202 | return result; 203 | }, 204 | async OCRbasedOnFileBuffer( 205 | fileBuffer: any, 206 | fileName: string, 207 | language: string = "eng", 208 | mode: string = "text" 209 | ) { 210 | const data = new FormData(); 211 | data.append("image", fileBuffer, { 212 | filename: fileName, 213 | }); 214 | 215 | const options = { 216 | method: "POST", 217 | url: "https://text-to-anything.p.rapidapi.com/ocr", 218 | params: { 219 | language, 220 | mode, 221 | }, 222 | headers: { 223 | "X-RapidAPI-Key": await getRapidAPIKey(), 224 | ...data.getHeaders(), 225 | }, 226 | data, 227 | }; 228 | 229 | const response = await axios.request(options).catch((e) => { 230 | logger.error("[TTA] " + e); 231 | }); 232 | 233 | if (!response) { 234 | return []; 235 | } 236 | 237 | return response.data; 238 | }, 239 | _getRapidAPIKey: getRapidAPIKey, 240 | _handleRapidAPIError: handleRapidAPIError, 241 | }; 242 | 243 | async function addField( 244 | name: string, 245 | type: string, 246 | meta: any = {}, 247 | collection = "TTA_htmltemplates" 248 | ) { 249 | try { 250 | await fieldsService.createField(collection, { 251 | field: name, 252 | type, 253 | meta, 254 | }); 255 | } catch (error) { 256 | logger.warn( 257 | "[TTA] Error while creating '" + 258 | name + 259 | "' in the collection " + 260 | collection + 261 | ": " 262 | ); 263 | console.error(error); 264 | } 265 | } 266 | 267 | async function handleRapidAPIError(error: any): Promise { 268 | let errorStream: any; 269 | if (error.response) { 270 | errorStream = error.response.data; 271 | } else { 272 | // Something happened in setting up the request that triggered an Error 273 | logger.error("[TTA] Request setup error:", error.message); 274 | throw new Error(error.message); 275 | } 276 | 277 | return await new Promise((_res, rej) => { 278 | let error = ""; 279 | // Log the error response data to the console 280 | errorStream.on("data", (chunk: any) => { 281 | error += chunk.toString(); 282 | }); 283 | 284 | // Close the connection when the error stream ends 285 | errorStream.on("end", () => { 286 | logger.error("[TTA] " + error); 287 | rej(error); 288 | }); 289 | }); 290 | } 291 | 292 | async function getRapidAPIKey() { 293 | const settingsService = new services.SettingsService({ 294 | schema: await getSchema(), 295 | }); 296 | 297 | return (await settingsService.readSingleton({ fields: ["TTA_KEY"] })) 298 | .TTA_KEY; 299 | } 300 | }); 301 | }); 302 | -------------------------------------------------------------------------------- /installationhook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Copyright 2025 Bart Don (Attacler) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /ocr/OCR-interface/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /ocr/OCR-interface/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-PDFTemplateInterface", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-interface" 8 | ], 9 | "directus:extension": { 10 | "type": "interface", 11 | "path": "dist/index.js", 12 | "source": "src/index.ts", 13 | "host": "^9.22.1" 14 | }, 15 | "scripts": { 16 | "build": "directus-extension build", 17 | "dev": "directus-extension build -w --no-minify" 18 | }, 19 | "devDependencies": { 20 | "@directus/extensions-sdk": "9.22.1", 21 | "typescript": "^5.3.3", 22 | "vue": "^3.3.11" 23 | }, 24 | "dependencies": { 25 | "pdfjs-dist": "^5.2.133" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineInterface } from "@directus/extensions-sdk"; 2 | import { computed } from "vue"; 3 | import InterfaceComponent from "./interface.vue"; 4 | import { useStores } from "@directus/extensions-sdk"; 5 | import { languages } from "./languages"; 6 | 7 | export default defineInterface({ 8 | id: "tta-ocr-interface", 9 | name: "OCR interface", 10 | icon: "camera_video", 11 | description: "Use OCR to fill fields. (Text to anything)", 12 | hideLabel: true, 13 | hideLoader: true, 14 | component: InterfaceComponent, 15 | types: ["alias"], 16 | localTypes: ["presentation"], 17 | options: [ 18 | { 19 | field: "language", 20 | name: "Language", 21 | type: "dropdown", 22 | meta: { 23 | interface: "select-dropdown", 24 | options: { 25 | choices: languages, 26 | }, 27 | }, 28 | }, 29 | ], 30 | }); 31 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/interface.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 192 | 193 | 214 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/languages.ts: -------------------------------------------------------------------------------- 1 | export const languages = [ 2 | { value: "eng", text: "English" }, 3 | { value: "por", text: "Portuguese" }, 4 | { value: "fra", text: "French" }, 5 | { value: "osd", text: "Orientation and Script Detection" }, 6 | { value: "chi_sim", text: "Chinese (Simplified)" }, 7 | { value: "spa", text: "Spanish" }, 8 | { value: "deu", text: "German" }, 9 | { value: "chi_tra", text: "Chinese (Traditional)" }, 10 | { value: "heb", text: "Hebrew" }, 11 | { value: "kor", text: "Korean" }, 12 | { value: "jpn", text: "Japanese" }, 13 | { value: "rus", text: "Russian" }, 14 | { value: "nld", text: "Dutch" }, 15 | { value: "hin", text: "Hindi" }, 16 | { value: "ita", text: "Italian" }, 17 | { value: "jpn_vert", text: "Japanese (Vertical)" }, 18 | { value: "pol", text: "Polish" }, 19 | { value: "ron", text: "Romanian" }, 20 | { value: "mar", text: "Marathi" }, 21 | { value: "ukr", text: "Ukrainian" }, 22 | { value: "mal", text: "Malayalam" }, 23 | { value: "tam", text: "Tamil" }, 24 | { value: "guj", text: "Gujarati" }, 25 | { value: "tha", text: "Thai" }, 26 | { value: "kan", text: "Kannada" }, 27 | { value: "vie", text: "Vietnamese" }, 28 | { value: "tel", text: "Telugu" }, 29 | { value: "swe", text: "Swedish" }, 30 | { value: "tur", text: "Turkish" }, 31 | { value: "nor", text: "Norwegian" }, 32 | { value: "ces", text: "Czech" }, 33 | { value: "ben", text: "Bengali" }, 34 | { value: "pan", text: "Punjabi" }, 35 | { value: "equ", text: "Math / Equation Detection" }, 36 | { value: "ell", text: "Greek" }, 37 | { value: "bul", text: "Bulgarian" }, 38 | { value: "lat", text: "Latin" }, 39 | { value: "kur", text: "Kurdish" }, 40 | { value: "ori", text: "Odia" }, 41 | { value: "kat", text: "Georgian" }, 42 | { value: "amh", text: "Amharic" }, 43 | { value: "kaz", text: "Kazakh" }, 44 | { value: "cat", text: "Catalan" }, 45 | { value: "nep", text: "Nepali" }, 46 | { value: "urd", text: "Urdu" }, 47 | { value: "khm", text: "Khmer" }, 48 | { value: "dan", text: "Danish" }, 49 | { value: "chi_sim_vert", text: "Chinese (Simplified, Vertical)" }, 50 | { value: "uzb", text: "Uzbek (Latin)" }, 51 | { value: "slv", text: "Slovenian" }, 52 | { value: "mkd", text: "Macedonian" }, 53 | { value: "tgl", text: "Tagalog" }, 54 | { value: "srp", text: "Serbian (Cyrillic)" }, 55 | { value: "hrv", text: "Croatian" }, 56 | { value: "tir", text: "Tigrinya" }, 57 | { value: "syr", text: "Syriac" }, 58 | { value: "lao", text: "Lao" }, 59 | { value: "fin", text: "Finnish" }, 60 | { value: "est", text: "Estonian" }, 61 | { value: "bos", text: "Bosnian" }, 62 | { value: "uig", text: "Uyghur" }, 63 | { value: "sin", text: "Sinhala" }, 64 | { value: "hye", text: "Armenian" }, 65 | { value: "eus", text: "Basque" }, 66 | { value: "sqi", text: "Albanian" }, 67 | { value: "isl", text: "Icelandic" }, 68 | { value: "bel", text: "Belarusian" }, 69 | { value: "aze", text: "Azerbaijani (Latin)" }, 70 | { value: "pus", text: "Pashto" }, 71 | { value: "oci", text: "Occitan" }, 72 | { value: "lit", text: "Lithuanian" }, 73 | { value: "jav", text: "Javanese" }, 74 | { value: "hun", text: "Hungarian" }, 75 | { value: "grc", text: "Ancient Greek" }, 76 | { value: "gle", text: "Irish" }, 77 | { value: "frm", text: "Middle French" }, 78 | { value: "afr", text: "Afrikaans" }, 79 | { value: "uzb_cyrl", text: "Uzbek (Cyrillic)" }, 80 | { value: "spa_old", text: "Old Spanish" }, 81 | { value: "snd", text: "Sindhi" }, 82 | { value: "mya", text: "Burmese" }, 83 | { value: "iku", text: "Inuktitut" }, 84 | { value: "fil", text: "Filipino" }, 85 | { value: "fas", text: "Persian" }, 86 | { value: "fao", text: "Faroese" }, 87 | { value: "dzo", text: "Dzongkha" }, 88 | { value: "cym", text: "Welsh" }, 89 | { value: "aze_cyrl", text: "Azerbaijani (Cyrillic)" }, 90 | { value: "ind", text: "Indonesian" }, 91 | { value: "ara", text: "Arabic" }, 92 | { value: "yid", text: "Yiddish" }, 93 | { value: "ton", text: "Tongan" }, 94 | { value: "tgk", text: "Tajik" }, 95 | { value: "srp_latn", text: "Serbian (Latin)" }, 96 | { value: "slk_frak", text: "Slovak (Fraktur)" }, 97 | { value: "slk", text: "Slovak" }, 98 | { value: "san", text: "Sanskrit" }, 99 | { value: "msa", text: "Malay" }, 100 | { value: "mri", text: "Maori" }, 101 | { value: "mlt", text: "Maltese" }, 102 | { value: "lav", text: "Latvian" }, 103 | { value: "kur_ara", text: "Kurdish (Arabic)" }, 104 | { value: "kor_vert", text: "Korean (Vertical)" }, 105 | { value: "kmr", text: "Kurmanji" }, 106 | { value: "kir", text: "Kyrgyz" }, 107 | { value: "hat", text: "Haitian Creole" }, 108 | { value: "glg", text: "Galician" }, 109 | { value: "fry", text: "Frisian" }, 110 | { value: "epo", text: "Esperanto" }, 111 | { value: "div", text: "Divehi" }, 112 | { value: "chr", text: "Cherokee" }, 113 | { value: "bod", text: "Tibetan" }, 114 | { value: "asm", text: "Assamese" }, 115 | { value: "yor", text: "Yoruba" }, 116 | { value: "tat", text: "Tatar" }, 117 | { value: "sun", text: "Sundanese" }, 118 | { value: "occ", text: "Occitan (alternative)" }, 119 | { value: "mon", text: "Mongolian" }, 120 | { value: "ita_old", text: "Old Italian" }, 121 | { value: "gla", text: "Scottish Gaelic" }, 122 | { value: "frk", text: "Frankish" }, 123 | { value: "enm", text: "Middle English" }, 124 | { value: "deu_frak", text: "German (Fraktur)" }, 125 | { value: "dan_frak", text: "Danish (Fraktur)" }, 126 | { value: "chi_tra_vert", text: "Chinese (Traditional, Vertical)" }, 127 | { value: "ceb", text: "Cebuano" }, 128 | { value: "bre", text: "Breton" }, 129 | { value: "swa", text: "Swahili" }, 130 | { value: "que", text: "Quechua" }, 131 | { value: "ltz", text: "Luxembourgish" }, 132 | { value: "kat_old", text: "Old Georgian" }, 133 | { value: "cos", text: "Corsican" }, 134 | ]; 135 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/ocredrag.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 93 | 94 | 102 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/renderOCRResponse.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 275 | 276 | 318 | -------------------------------------------------------------------------------- /ocr/OCR-interface/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /ocr/OCR-interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /ocr/OCR-operator/api.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApi } from "@directus/extensions-sdk"; 2 | 3 | type Options = { 4 | fileID: string; 5 | mode: string; 6 | language: string; 7 | }; 8 | 9 | export default defineOperationApi({ 10 | id: "ttaocr", 11 | handler: async ({ fileID, language, mode }) => { 12 | return await (globalThis as any).TTA.OCRBasedOnAsset( 13 | fileID, 14 | language, 15 | mode 16 | ); 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /ocr/OCR-operator/app.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApp } from "@directus/extensions-sdk"; 2 | import { languages } from "./languages.ts"; 3 | 4 | export default defineOperationApp({ 5 | id: "ttaocr", 6 | name: "TTA OCR", 7 | icon: "camera_video", 8 | description: "TTA scan image with OCR", 9 | overview: ({ fileID, mode, language }) => [ 10 | { 11 | label: "Mode", 12 | text: mode, 13 | }, 14 | { 15 | label: "Language", 16 | text: language, 17 | }, 18 | { 19 | label: "File ID", 20 | text: fileID, 21 | }, 22 | ], 23 | options: [ 24 | { 25 | field: "fileID", 26 | name: "File ID", 27 | type: "string", 28 | meta: { 29 | width: "full", 30 | interface: "input", 31 | }, 32 | }, 33 | { 34 | field: "mode", 35 | name: "Mode", 36 | type: "string", 37 | meta: { 38 | interface: "select-dropdown", 39 | options: { 40 | choices: [ 41 | { text: "Text", value: "text" }, 42 | { text: "Horc", value: "horc" }, 43 | { text: "Blocks", value: "blocks" }, 44 | ], 45 | }, 46 | }, 47 | }, 48 | { 49 | field: "language", 50 | name: "Language", 51 | type: "dropdown", 52 | meta: { 53 | interface: "select-dropdown", 54 | options: { 55 | choices: languages, 56 | }, 57 | }, 58 | }, 59 | ], 60 | }); 61 | -------------------------------------------------------------------------------- /ocr/OCR-operator/languages.ts: -------------------------------------------------------------------------------- 1 | export const languages = [ 2 | { value: "eng", text: "English" }, 3 | { value: "por", text: "Portuguese" }, 4 | { value: "fra", text: "French" }, 5 | { value: "osd", text: "Orientation and Script Detection" }, 6 | { value: "chi_sim", text: "Chinese (Simplified)" }, 7 | { value: "spa", text: "Spanish" }, 8 | { value: "deu", text: "German" }, 9 | { value: "chi_tra", text: "Chinese (Traditional)" }, 10 | { value: "heb", text: "Hebrew" }, 11 | { value: "kor", text: "Korean" }, 12 | { value: "jpn", text: "Japanese" }, 13 | { value: "rus", text: "Russian" }, 14 | { value: "nld", text: "Dutch" }, 15 | { value: "hin", text: "Hindi" }, 16 | { value: "ita", text: "Italian" }, 17 | { value: "jpn_vert", text: "Japanese (Vertical)" }, 18 | { value: "pol", text: "Polish" }, 19 | { value: "ron", text: "Romanian" }, 20 | { value: "mar", text: "Marathi" }, 21 | { value: "ukr", text: "Ukrainian" }, 22 | { value: "mal", text: "Malayalam" }, 23 | { value: "tam", text: "Tamil" }, 24 | { value: "guj", text: "Gujarati" }, 25 | { value: "tha", text: "Thai" }, 26 | { value: "kan", text: "Kannada" }, 27 | { value: "vie", text: "Vietnamese" }, 28 | { value: "tel", text: "Telugu" }, 29 | { value: "swe", text: "Swedish" }, 30 | { value: "tur", text: "Turkish" }, 31 | { value: "nor", text: "Norwegian" }, 32 | { value: "ces", text: "Czech" }, 33 | { value: "ben", text: "Bengali" }, 34 | { value: "pan", text: "Punjabi" }, 35 | { value: "equ", text: "Math / Equation Detection" }, 36 | { value: "ell", text: "Greek" }, 37 | { value: "bul", text: "Bulgarian" }, 38 | { value: "lat", text: "Latin" }, 39 | { value: "kur", text: "Kurdish" }, 40 | { value: "ori", text: "Odia" }, 41 | { value: "kat", text: "Georgian" }, 42 | { value: "amh", text: "Amharic" }, 43 | { value: "kaz", text: "Kazakh" }, 44 | { value: "cat", text: "Catalan" }, 45 | { value: "nep", text: "Nepali" }, 46 | { value: "urd", text: "Urdu" }, 47 | { value: "khm", text: "Khmer" }, 48 | { value: "dan", text: "Danish" }, 49 | { value: "chi_sim_vert", text: "Chinese (Simplified, Vertical)" }, 50 | { value: "uzb", text: "Uzbek (Latin)" }, 51 | { value: "slv", text: "Slovenian" }, 52 | { value: "mkd", text: "Macedonian" }, 53 | { value: "tgl", text: "Tagalog" }, 54 | { value: "srp", text: "Serbian (Cyrillic)" }, 55 | { value: "hrv", text: "Croatian" }, 56 | { value: "tir", text: "Tigrinya" }, 57 | { value: "syr", text: "Syriac" }, 58 | { value: "lao", text: "Lao" }, 59 | { value: "fin", text: "Finnish" }, 60 | { value: "est", text: "Estonian" }, 61 | { value: "bos", text: "Bosnian" }, 62 | { value: "uig", text: "Uyghur" }, 63 | { value: "sin", text: "Sinhala" }, 64 | { value: "hye", text: "Armenian" }, 65 | { value: "eus", text: "Basque" }, 66 | { value: "sqi", text: "Albanian" }, 67 | { value: "isl", text: "Icelandic" }, 68 | { value: "bel", text: "Belarusian" }, 69 | { value: "aze", text: "Azerbaijani (Latin)" }, 70 | { value: "pus", text: "Pashto" }, 71 | { value: "oci", text: "Occitan" }, 72 | { value: "lit", text: "Lithuanian" }, 73 | { value: "jav", text: "Javanese" }, 74 | { value: "hun", text: "Hungarian" }, 75 | { value: "grc", text: "Ancient Greek" }, 76 | { value: "gle", text: "Irish" }, 77 | { value: "frm", text: "Middle French" }, 78 | { value: "afr", text: "Afrikaans" }, 79 | { value: "uzb_cyrl", text: "Uzbek (Cyrillic)" }, 80 | { value: "spa_old", text: "Old Spanish" }, 81 | { value: "snd", text: "Sindhi" }, 82 | { value: "mya", text: "Burmese" }, 83 | { value: "iku", text: "Inuktitut" }, 84 | { value: "fil", text: "Filipino" }, 85 | { value: "fas", text: "Persian" }, 86 | { value: "fao", text: "Faroese" }, 87 | { value: "dzo", text: "Dzongkha" }, 88 | { value: "cym", text: "Welsh" }, 89 | { value: "aze_cyrl", text: "Azerbaijani (Cyrillic)" }, 90 | { value: "ind", text: "Indonesian" }, 91 | { value: "ara", text: "Arabic" }, 92 | { value: "yid", text: "Yiddish" }, 93 | { value: "ton", text: "Tongan" }, 94 | { value: "tgk", text: "Tajik" }, 95 | { value: "srp_latn", text: "Serbian (Latin)" }, 96 | { value: "slk_frak", text: "Slovak (Fraktur)" }, 97 | { value: "slk", text: "Slovak" }, 98 | { value: "san", text: "Sanskrit" }, 99 | { value: "msa", text: "Malay" }, 100 | { value: "mri", text: "Maori" }, 101 | { value: "mlt", text: "Maltese" }, 102 | { value: "lav", text: "Latvian" }, 103 | { value: "kur_ara", text: "Kurdish (Arabic)" }, 104 | { value: "kor_vert", text: "Korean (Vertical)" }, 105 | { value: "kmr", text: "Kurmanji" }, 106 | { value: "kir", text: "Kyrgyz" }, 107 | { value: "hat", text: "Haitian Creole" }, 108 | { value: "glg", text: "Galician" }, 109 | { value: "fry", text: "Frisian" }, 110 | { value: "epo", text: "Esperanto" }, 111 | { value: "div", text: "Divehi" }, 112 | { value: "chr", text: "Cherokee" }, 113 | { value: "bod", text: "Tibetan" }, 114 | { value: "asm", text: "Assamese" }, 115 | { value: "yor", text: "Yoruba" }, 116 | { value: "tat", text: "Tatar" }, 117 | { value: "sun", text: "Sundanese" }, 118 | { value: "occ", text: "Occitan (alternative)" }, 119 | { value: "mon", text: "Mongolian" }, 120 | { value: "ita_old", text: "Old Italian" }, 121 | { value: "gla", text: "Scottish Gaelic" }, 122 | { value: "frk", text: "Frankish" }, 123 | { value: "enm", text: "Middle English" }, 124 | { value: "deu_frak", text: "German (Fraktur)" }, 125 | { value: "dan_frak", text: "Danish (Fraktur)" }, 126 | { value: "chi_tra_vert", text: "Chinese (Traditional, Vertical)" }, 127 | { value: "ceb", text: "Cebuano" }, 128 | { value: "bre", text: "Breton" }, 129 | { value: "swa", text: "Swahili" }, 130 | { value: "que", text: "Quechua" }, 131 | { value: "ltz", text: "Luxembourgish" }, 132 | { value: "kat_old", text: "Old Georgian" }, 133 | { value: "cos", text: "Corsican" }, 134 | ]; 135 | -------------------------------------------------------------------------------- /ocr/OCR-operator/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-texttoanything", 3 | "description": "Generate PDF`s/QRcodes/Barcodes or use OCR within Directus!", 4 | "version": "1.5.1", 5 | "icon": "text_fields", 6 | "author": { 7 | "name": "Attacler/Bart", 8 | "email": "bart@attacler.com" 9 | }, 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/Attacler/TextToAnything-Directus/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/Attacler/TextToAnything-Directus.git" 17 | }, 18 | "keywords": [ 19 | "directus", 20 | "directus-extension", 21 | "directus-custom-bundle" 22 | ], 23 | "files": [ 24 | "dist" 25 | ], 26 | "directus:extension": { 27 | "type": "bundle", 28 | "path": { 29 | "app": "dist/app.js", 30 | "api": "dist/api.js" 31 | }, 32 | "entries": [ 33 | { 34 | "type": "operation", 35 | "name": "GenerateBarcode", 36 | "source": { 37 | "app": "GenerateBarcode/src/app.ts", 38 | "api": "GenerateBarcode/src/api.ts" 39 | } 40 | }, 41 | { 42 | "type": "operation", 43 | "name": "GeneratePDF", 44 | "source": { 45 | "app": "pdf/GeneratePDF/src/app.ts", 46 | "api": "pdf/GeneratePDF/src/api.ts" 47 | } 48 | }, 49 | { 50 | "type": "operation", 51 | "name": "GeneratePDFFromTemplate", 52 | "source": { 53 | "app": "pdf/GeneratePDFGenerateFromTemplate/src/app.ts", 54 | "api": "pdf/GeneratePDFGenerateFromTemplate/src/api.ts" 55 | } 56 | }, 57 | { 58 | "type": "operation", 59 | "name": "GenerateQRCode", 60 | "source": { 61 | "app": "GenerateQRCode/src/app.ts", 62 | "api": "GenerateQRCode/src/api.ts" 63 | } 64 | }, 65 | { 66 | "type": "hook", 67 | "name": "bootstrap", 68 | "source": "installationhook/src/index.ts" 69 | }, 70 | { 71 | "type": "module", 72 | "name": "settings module", 73 | "source": "settingsmodule/src/index.ts" 74 | }, 75 | { 76 | "type": "interface", 77 | "name": "PDF template selector", 78 | "source": "pdf/PDFTemplateSelector/src/index.ts" 79 | }, 80 | { 81 | "type": "interface", 82 | "name": "PDF generator interface", 83 | "source": "pdf/GeneratePDFFromTemplateInterface/src/index.ts" 84 | }, 85 | { 86 | "type": "interface", 87 | "name": "ocr/OCR-interface", 88 | "source": "ocr/OCR-interface/src/index.ts" 89 | }, 90 | { 91 | "type": "endpoint", 92 | "name": "Text To Anything endpoint", 93 | "source": "TTA-endpoint/src/index.ts" 94 | }, 95 | { 96 | "type": "operation", 97 | "name": "OCR-operator", 98 | "source": { 99 | "app": "ocr/OCR-operator/app.ts", 100 | "api": "ocr/OCR-operator/api.ts" 101 | } 102 | } 103 | ], 104 | "host": "^10.0.0 || ^11.0.0" 105 | }, 106 | "scripts": { 107 | "build": "directus-extension build", 108 | "dev": "directus-extension build -w --no-minify", 109 | "add": "directus-extension add" 110 | }, 111 | "devDependencies": { 112 | "@directus/extensions-sdk": "9.22.1", 113 | "@types/node": "^22.15.3", 114 | "typescript": "^5.8.3", 115 | "vue": "^3.5.13" 116 | }, 117 | "dependencies": { 118 | "html-format": "^1.1.6" 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /pdf/GeneratePDF/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /pdf/GeneratePDF/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-GeneratePDF", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-operation" 8 | ], 9 | "directus:extension": { 10 | "type": "operation", 11 | "path": { 12 | "app": "../../extensions/operations/GeneratePDF/app.js", 13 | "api": "../../extensions/operations/GeneratePDF/api.js" 14 | }, 15 | "source": { 16 | "app": "src/app.ts", 17 | "api": "src/api.ts" 18 | }, 19 | "host": "^9.22.1" 20 | }, 21 | "scripts": { 22 | "build": "directus-extension build", 23 | "dev": "directus-extension build -w --no-minify" 24 | }, 25 | "devDependencies": { 26 | "@directus/extensions-sdk": "9.22.1", 27 | "@types/node": "^18.11.18", 28 | "typescript": "^4.9.4", 29 | "vue": "^3.2.45" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pdf/GeneratePDF/src/api.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApi } from "@directus/extensions-sdk"; 2 | 3 | type Options = { 4 | "RapidAPI token": string; 5 | filename: string; 6 | pdfoptions: any; 7 | }; 8 | 9 | export default defineOperationApi({ 10 | id: "ttapdf", 11 | handler: async (context) => { 12 | return await (globalThis as any).TTA.generatePDF(context); 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /pdf/GeneratePDF/src/app.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApp } from "@directus/extensions-sdk"; 2 | 3 | export default defineOperationApp({ 4 | id: "ttapdf", 5 | name: "TTA generate PDF", 6 | icon: "picture_as_pdf", 7 | description: "Generate a PDF trough Text to anything!", 8 | overview: ({ filename }) => [ 9 | { 10 | label: "File name", 11 | text: filename, 12 | }, 13 | ], 14 | options: [ 15 | { 16 | field: "filename", 17 | name: "File name", 18 | type: "string", 19 | meta: { 20 | width: "full", 21 | interface: "input", 22 | }, 23 | }, 24 | { 25 | field: "pdfoptions", 26 | name: "Options", 27 | type: "json", 28 | meta: { 29 | width: "full", 30 | interface: "input-code", 31 | options: { 32 | language: "json", 33 | placeholder: JSON.stringify( 34 | { 35 | html: "

Hello world!

", 36 | format: "A4", 37 | landscape: false, 38 | margin: 10, 39 | marginRight: 5, 40 | marginLeft: 5, 41 | }, 42 | null, 43 | 2 44 | ), 45 | template: JSON.stringify( 46 | { 47 | html: "

Hello world!

", 48 | format: "A4", 49 | landscape: false, 50 | margin: 10, 51 | marginRight: 5, 52 | marginLeft: 5, 53 | }, 54 | null, 55 | 2 56 | ), 57 | }, 58 | }, 59 | }, 60 | ], 61 | }); 62 | -------------------------------------------------------------------------------- /pdf/GeneratePDF/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /pdf/GeneratePDF/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-PDFTemplateInterface", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-interface" 8 | ], 9 | "directus:extension": { 10 | "type": "interface", 11 | "path": "dist/index.js", 12 | "source": "src/index.ts", 13 | "host": "^9.22.1" 14 | }, 15 | "scripts": { 16 | "build": "directus-extension build", 17 | "dev": "directus-extension build -w --no-minify" 18 | }, 19 | "devDependencies": { 20 | "@directus/extensions-sdk": "9.22.1", 21 | "typescript": "^5.3.3", 22 | "vue": "^3.3.11" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineInterface } from "@directus/extensions-sdk"; 2 | import { computed } from "vue"; 3 | import InterfaceComponent from "./interface.vue"; 4 | import { useStores } from "@directus/extensions-sdk"; 5 | 6 | export default defineInterface({ 7 | id: "tta-download-interface", 8 | name: "Download interface", 9 | icon: "sim_card_download", 10 | description: "Download files based on a flow. (Text to anything)", 11 | hideLabel: true, 12 | hideLoader: true, 13 | component: InterfaceComponent, 14 | options: () => { 15 | const { useFlowsStore } = useStores(); 16 | const flowStore = useFlowsStore(); 17 | 18 | const flowOptions = computed(() => 19 | flowStore.flows 20 | .filter( 21 | (flow: any) => 22 | flow.trigger === "webhook" && flow.options.method == "POST" 23 | ) 24 | .map((flow: any) => { 25 | return { text: flow.name, value: flow.id }; 26 | }) 27 | ); 28 | return [ 29 | { 30 | field: "label", 31 | type: "string", 32 | name: "$t:label", 33 | meta: { 34 | width: "full", 35 | interface: "system-input-translated-string", 36 | options: { 37 | placeholder: "$t:label", 38 | }, 39 | }, 40 | }, 41 | { 42 | field: "flow", 43 | name: "$t:operations.trigger.flow", 44 | type: "string", 45 | meta: { 46 | width: "full", 47 | interface: "select-dropdown", 48 | options: { 49 | choices: flowOptions, 50 | iconRight: "bolt", 51 | placeholder: "$t:a_flow_uuid", 52 | }, 53 | }, 54 | }, 55 | ]; 56 | }, 57 | types: ["string"], 58 | }); 59 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/src/interface.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /pdf/GeneratePDFFromTemplateInterface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-GeneratePDF", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-operation" 8 | ], 9 | "directus:extension": { 10 | "type": "operation", 11 | "path": { 12 | "app": "../../extensions/operations/GeneratePDF/app.js", 13 | "api": "../../extensions/operations/GeneratePDF/api.js" 14 | }, 15 | "source": { 16 | "app": "src/app.ts", 17 | "api": "src/api.ts" 18 | }, 19 | "host": "^9.22.1" 20 | }, 21 | "scripts": { 22 | "build": "directus-extension build", 23 | "dev": "directus-extension build -w --no-minify" 24 | }, 25 | "devDependencies": { 26 | "@directus/extensions-sdk": "9.22.1", 27 | "@types/node": "^18.11.18", 28 | "typescript": "^4.9.4", 29 | "vue": "^3.2.45" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/src/api.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApi } from "@directus/extensions-sdk"; 2 | 3 | type Options = { 4 | "RapidAPI token": string; 5 | filename: string; 6 | pdfoptions: any; 7 | }; 8 | 9 | export default defineOperationApi({ 10 | id: "ttapdftemplate", 11 | handler: async (context) => { 12 | return await (globalThis as any).TTA.generatePDFFromTemplate(context); 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/src/app.ts: -------------------------------------------------------------------------------- 1 | import { defineOperationApp } from "@directus/extensions-sdk"; 2 | 3 | export default defineOperationApp({ 4 | id: "ttapdftemplate", 5 | name: "TTA generate PDF from template", 6 | icon: "picture_as_pdf", 7 | description: "Generate a PDF based on a template trough Text to anything!", 8 | overview: ({ filename }) => [ 9 | { 10 | label: "File name", 11 | text: filename, 12 | }, 13 | ], 14 | options: [ 15 | { 16 | field: "filename", 17 | name: "File name", 18 | type: "string", 19 | meta: { 20 | width: "full", 21 | interface: "input", 22 | }, 23 | }, 24 | { 25 | field: "template", 26 | name: "Template", 27 | type: "string", 28 | meta: { 29 | interface: "TTA-pdf-template-selector", 30 | options: {}, 31 | }, 32 | }, 33 | { 34 | field: "templatevariables", 35 | name: "Template variables", 36 | type: "json", 37 | meta: { 38 | width: "full", 39 | interface: "input-code", 40 | options: { 41 | language: "json", 42 | }, 43 | }, 44 | }, 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /pdf/GeneratePDFGenerateFromTemplate/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-PDFTemplateSelector", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-interface" 8 | ], 9 | "directus:extension": { 10 | "type": "interface", 11 | "path": "dist/index.js", 12 | "source": "src/index.ts", 13 | "host": "^9.22.1" 14 | }, 15 | "scripts": { 16 | "build": "directus-extension build", 17 | "dev": "directus-extension build -w --no-minify" 18 | }, 19 | "devDependencies": { 20 | "@directus/extensions-sdk": "9.22.1", 21 | "typescript": "^5.3.3", 22 | "vue": "^3.3.11" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineInterface } from "@directus/extensions-sdk"; 2 | import InterfaceComponent from "./interface.vue"; 3 | 4 | export default defineInterface({ 5 | id: "TTA-pdf-template-selector", 6 | name: "PDF template selector", 7 | icon: "picture_as_pdf", 8 | description: "Selector for a PDF template for Text To Anything", 9 | component: InterfaceComponent, 10 | options: null, 11 | types: ["string"], 12 | }); 13 | -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/src/interface.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 36 | -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /pdf/PDFTemplateSelector/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "lib": ["ES2019", "DOM"], 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noFallthroughCasesInSwitch": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "noUnusedLocals": true, 13 | "noUncheckedIndexedAccess": true, 14 | "noUnusedParameters": true, 15 | "alwaysStrict": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "resolveJsonModule": false, 21 | "skipLibCheck": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | "rootDir": "./src" 26 | }, 27 | "include": ["./src/**/*.ts"] 28 | } 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Directus TextToAnything extension 2 | 3 | ## Introduction 4 | 5 | Do you want to create PDFs, barcodes, and QR codes or use OCR within Directus? 6 | This extension bundle offers the required operations to achieve that! 7 | 8 | The installation process is explained in [The site](https://texttoanything.nl/docs/directus/). 9 | 10 | ## Features 11 | 12 |
13 |

OCR based on a file

14 | More info on the wiki.
15 |

OCR as interface

16 | 17 |

OCR inside of flows

18 |
19 |

OCR inside extensions

20 | Check the wiki for more information on using OCR inside of extensions. 21 |
22 | 23 |
24 |

PDF generation based on HTML

25 | More info on the wiki.
26 |

HTML to PFD inside Flows

27 | 28 |

HTML to PDF inside extensions


29 | 30 | ```js 31 | const fileID = await globalThis.TTA.generatePDF({ 32 | pdfoptions: { 33 | html: "HTML body", 34 | footer: "HTML footer", 35 | footer: "HTML header", 36 | format: "A4", 37 | landscape: false, 38 | margin: 10, 39 | marginRight: 5, 40 | marginLeft: 500, 41 | }, 42 | filename: "file.pdf", 43 | }); 44 | ``` 45 | 46 |
47 | 48 |
49 |

HTML PDF templates

50 | More info on the wiki.
51 | Since creating a PDF template can be challenging when working solely with strings, this extension also includes a built-in template editor.
52 | 53 | PDF generation based on a template can be done in 2 ways:
54 |

Template to PDF inside Flows

55 | 56 |

HTML to PDF inside extensions


57 | 58 | ```js 59 | const fileID = await globalThis.TTA.generatePDFFromTemplate({ 60 | template: templateIDHere, 61 | templatevariables: { variableOne: "A", variableTwo: "B" }, 62 | }); 63 | ``` 64 | 65 |
66 | 67 |
68 |

QR code generation

69 | More info on the wiki.
70 |

QR code generation inside Flows

71 | 72 |

QR code generation inside extensions


73 | 74 | ```js 75 | const fileID = await globalThis.TTA.generateQRCode({ 76 | content: "Your barcode content!", 77 | darkColor: "fff", 78 | lightColor: "000", 79 | margin: 2, 80 | width: 200, 81 | }); 82 | ``` 83 | 84 |
85 | 86 |
87 |

Barcode generation

88 | More info on the site.
89 |

Barcode generation inside Flows

90 | 91 |

Barcode generation inside extensions


92 | 93 | ```js 94 | const fileID = await globalThis.TTA.generateBarCode({ 95 | barcodeContent: "Your barcode content!", 96 | barcodeType: "code128", 97 | scale: 2, 98 | height: 10, 99 | includetext: true, 100 | }); 101 | ``` 102 | 103 |
104 | 105 |
106 |

Download file interface from a flow

107 | More info on the site.
108 | The interface will display a button and download the file id returned by a flow, for example:
109 | 110 |
111 |
112 | 113 |
114 |

Flow logs explorer

115 | More info on the website.
116 | The module will show flow logs and let you filter on them:
117 | 118 |
119 |
120 | 121 | If there are any questions or bugs, please create an issue.
122 | You can also join our [Discord](https://discord.gg/dbEWUHGmnr) if you need direct support. 123 | 124 | ## Guides 125 | 126 | [How to generate invoice PDFs](https://attacler.medium.com/generating-invoice-pdfs-with-texttoanything-in-directus-e81c324010ac) 127 | 128 | ## FAQ 129 | 130 |
131 | 1. Is my data safe while using TTA? 132 |
133 | Yes — we do not store any of the content you generate or process on our servers.
134 | If you have any concerns regarding data security, feel free to reach out to us via our Discord. 135 |
136 | 137 |
138 | 2. Why does this extension require a RapidAPI key? 139 |
140 | This extension relies on a RapidAPI key for the following reasons:
141 | - To offloading resources, for example generating a PDF from HTML requires alot of system packages and causes extra load on your system
142 | - To support and fund ongoing development and maintenance 143 |
144 | 145 |
146 | 3. How can I find or reset my RapidAPI key? 147 |
148 | You can refer to this guide for instructions on creating or rotating your RapidAPI key. 149 |
150 | 151 |
152 | 4. I have a question, issue, or feature request — where should I go? 153 |
154 | We welcome all feedback and contributions. Please open an issue on GitHub or contact us in our Discord. 155 |
156 | 157 |
158 | 5. How do I cancel my subscription? 159 |
160 | To manage or cancel your subscription, please visit your RapidAPI billing settings. 161 |
162 | -------------------------------------------------------------------------------- /settingsmodule/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /settingsmodule/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-settingsmodule", 3 | "version": "1.0.0", 4 | "keywords": [ 5 | "directus", 6 | "directus-extension", 7 | "directus-custom-module" 8 | ], 9 | "directus:extension": { 10 | "type": "module", 11 | "path": "dist/index.js", 12 | "source": "src/index.ts", 13 | "host": "^9.22.1" 14 | }, 15 | "scripts": { 16 | "build": "directus-extension build", 17 | "dev": "directus-extension build -w --no-minify" 18 | }, 19 | "devDependencies": { 20 | "@directus/extensions-sdk": "9.22.1", 21 | "typescript": "^5.3.2", 22 | "vue": "^3.3.8" 23 | }, 24 | "dependencies": { 25 | "vue-json-pretty": "^2.4.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /settingsmodule/src/TTAnav.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /settingsmodule/src/components/dateTimePicker.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 71 | 72 | 82 | -------------------------------------------------------------------------------- /settingsmodule/src/components/displayFlowLogs.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 100 | 101 | 141 | 142 | 148 | -------------------------------------------------------------------------------- /settingsmodule/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const HTML_SPINNER = ` 2 | 3 | 4 | 33 | 34 | 35 |
36 |
37 |
Loading...
38 |
39 | 40 | `; 41 | -------------------------------------------------------------------------------- /settingsmodule/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineModule } from "@directus/extensions-sdk"; 2 | import ModuleComponent from "./pages/templates.vue"; 3 | import settings from "./pages/settings.vue"; 4 | import flowsLogExplorer from "./pages/flowLogsExplorer.vue"; 5 | 6 | export default defineModule({ 7 | id: "tta_settings", 8 | name: "Text to anything settings", 9 | icon: "text_fields", 10 | routes: [ 11 | { 12 | path: "", 13 | redirect: "/tta_settings/templates", 14 | }, 15 | { 16 | path: "templates", 17 | component: ModuleComponent, 18 | }, 19 | { 20 | path: "settings", 21 | component: settings, 22 | }, 23 | { 24 | path: "flowsLogExplorer", 25 | component: flowsLogExplorer, 26 | }, 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /settingsmodule/src/pages/flowLogsExplorer.vue: -------------------------------------------------------------------------------- 1 | 102 | 103 | 225 | 226 | 264 | -------------------------------------------------------------------------------- /settingsmodule/src/pages/settings.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 72 | 73 | 88 | -------------------------------------------------------------------------------- /settingsmodule/src/pages/templates.vue: -------------------------------------------------------------------------------- 1 |