@tstdl/base 0.93.62 → 0.93.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/genkit/helpers.d.ts +10 -0
- package/ai/genkit/helpers.js +14 -0
- package/ai/genkit/index.d.ts +2 -0
- package/ai/genkit/index.js +2 -0
- package/ai/genkit/module.d.ts +35 -0
- package/ai/genkit/module.js +56 -0
- package/ai/index.d.ts +1 -0
- package/ai/index.js +1 -0
- package/ai/prompts/format.d.ts +15 -0
- package/ai/prompts/format.js +17 -0
- package/ai/prompts/index.d.ts +3 -0
- package/ai/prompts/index.js +3 -0
- package/ai/prompts/instructions-formatter.d.ts +25 -0
- package/ai/prompts/instructions-formatter.js +166 -0
- package/ai/prompts/instructions.d.ts +3 -0
- package/ai/prompts/instructions.js +8 -0
- package/document-management/server/services/document-file.service.d.ts +2 -0
- package/document-management/server/services/document-file.service.js +10 -9
- package/document-management/server/services/document-management-ai.service.d.ts +1 -0
- package/document-management/server/services/document-management-ai.service.js +267 -133
- package/document-management/server/services/document.service.js +1 -2
- package/examples/document-management/main.js +6 -0
- package/json-path/json-path.js +1 -1
- package/orm/server/repository.js +4 -6
- package/package.json +10 -6
- package/pdf/utils.js +1 -1
- package/schema/converters/zod-converter.d.ts +1 -1
- package/schema/converters/zod-converter.js +2 -13
- package/schema/converters/zod-v3-converter.d.ts +3 -3
- package/utils/date-time.d.ts +6 -0
- package/utils/date-time.js +36 -1
- package/utils/file-reader.d.ts +0 -1
- package/utils/file-reader.js +4 -7
- package/utils/object/object.d.ts +4 -2
- package/utils/object/object.js +30 -21
- package/utils/stream/from-promise.js +2 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GenerateOptions, z } from 'genkit';
|
|
2
|
+
import type { SchemaTestable } from '../../schema/index.js';
|
|
3
|
+
import type { TypedOmit } from '../../types/types.js';
|
|
4
|
+
export type TstdlGenkitGenerationOptions<T, O extends z.ZodTypeAny> = TypedOmit<GenerateOptions<z.ZodType<NoInfer<T>>, O>, 'output'> & {
|
|
5
|
+
output?: TypedOmit<NonNullable<GenerateOptions['output']>, 'schema'> & {
|
|
6
|
+
schema?: SchemaTestable<T>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare function convertToGenkitSchema<T>(schema: SchemaTestable<T>): z.ZodType<T>;
|
|
10
|
+
export declare function genkitGenerationOptions<T, O extends z.ZodTypeAny>(options: TstdlGenkitGenerationOptions<T, O>): GenerateOptions<z.ZodType<T>, z.ZodType<O>>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { convertToZodV3Schema } from '../../schema/converters/zod-v3-converter.js';
|
|
2
|
+
import { isDefined } from '../../utils/type-guards.js';
|
|
3
|
+
export function convertToGenkitSchema(schema) {
|
|
4
|
+
return convertToZodV3Schema(schema); // eslint-disable-line @typescript-eslint/no-unsafe-return
|
|
5
|
+
}
|
|
6
|
+
export function genkitGenerationOptions(options) {
|
|
7
|
+
return {
|
|
8
|
+
...options,
|
|
9
|
+
output: {
|
|
10
|
+
...options.output,
|
|
11
|
+
schema: isDefined(options.output?.schema) ? convertToGenkitSchema(options.output.schema) : undefined,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { vertexAI } from '@genkit-ai/google-genai';
|
|
2
|
+
import { type Genkit, type GenkitOptions } from 'genkit';
|
|
3
|
+
/**
|
|
4
|
+
* Options for configuring the AI Module.
|
|
5
|
+
*/
|
|
6
|
+
export declare class GenkitModuleOptions {
|
|
7
|
+
/** Gemini API specific options. */
|
|
8
|
+
gemini?: {
|
|
9
|
+
/** Gemini API key */
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Vertex AI specific options. If provided, the service will use Vertex AI endpoints. */
|
|
13
|
+
vertex?: {
|
|
14
|
+
/** Google Cloud API key */
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
/** Google Cloud projectId */
|
|
17
|
+
projectId: string;
|
|
18
|
+
/** Google Cloud region */
|
|
19
|
+
location: string;
|
|
20
|
+
/** Path to the Google Cloud credentials file */
|
|
21
|
+
keyFile?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Plugins to register automatically */
|
|
24
|
+
plugins?: GenkitOptions['plugins'];
|
|
25
|
+
/** Default Genkit options */
|
|
26
|
+
options?: Omit<GenkitOptions, 'plugins'>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Configures the {@link AiService}.
|
|
30
|
+
* @param options The configuration options for the AI services.
|
|
31
|
+
*/
|
|
32
|
+
export declare function configureGenkit(options: GenkitModuleOptions): void;
|
|
33
|
+
export declare function injectGenkit(options?: GenkitOptions): Genkit;
|
|
34
|
+
declare const _injectModel: typeof vertexAI.model;
|
|
35
|
+
export { _injectModel as injectModel };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { googleAI, vertexAI } from '@genkit-ai/google-genai';
|
|
2
|
+
import { genkit } from 'genkit';
|
|
3
|
+
import { inject } from '../../injector/inject.js';
|
|
4
|
+
import { Injector } from '../../injector/injector.js';
|
|
5
|
+
import { isDefined, isNotNull } from '../../utils/type-guards.js';
|
|
6
|
+
/**
|
|
7
|
+
* Options for configuring the AI Module.
|
|
8
|
+
*/
|
|
9
|
+
export class GenkitModuleOptions {
|
|
10
|
+
/** Gemini API specific options. */
|
|
11
|
+
gemini;
|
|
12
|
+
/** Vertex AI specific options. If provided, the service will use Vertex AI endpoints. */
|
|
13
|
+
vertex;
|
|
14
|
+
/** Plugins to register automatically */
|
|
15
|
+
plugins;
|
|
16
|
+
/** Default Genkit options */
|
|
17
|
+
options;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configures the {@link AiService}.
|
|
21
|
+
* @param options The configuration options for the AI services.
|
|
22
|
+
*/
|
|
23
|
+
export function configureGenkit(options) {
|
|
24
|
+
Injector.register(GenkitModuleOptions, { useValue: options });
|
|
25
|
+
}
|
|
26
|
+
export function injectGenkit(options) {
|
|
27
|
+
const { vertex, gemini, ...moduleOptions } = inject(GenkitModuleOptions, undefined, { optional: true }) ?? {};
|
|
28
|
+
const vertexPlugin = isDefined(vertex)
|
|
29
|
+
? vertexAI({
|
|
30
|
+
apiKey: vertex.apiKey,
|
|
31
|
+
location: vertex.location,
|
|
32
|
+
projectId: vertex.projectId,
|
|
33
|
+
googleAuth: isDefined(vertex.keyFile) ? { keyFile: vertex.keyFile } : undefined,
|
|
34
|
+
})
|
|
35
|
+
: null;
|
|
36
|
+
const geminiPlugin = isDefined(gemini)
|
|
37
|
+
? googleAI({ apiKey: gemini.apiKey })
|
|
38
|
+
: null;
|
|
39
|
+
return genkit({
|
|
40
|
+
...moduleOptions.options,
|
|
41
|
+
...options,
|
|
42
|
+
plugins: [
|
|
43
|
+
geminiPlugin,
|
|
44
|
+
vertexPlugin,
|
|
45
|
+
...(moduleOptions.plugins ?? []),
|
|
46
|
+
...(options?.plugins ?? []),
|
|
47
|
+
].filter(isNotNull),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function injectModel(...args) {
|
|
51
|
+
const moduleOptions = inject(GenkitModuleOptions, undefined, { optional: true }) ?? {};
|
|
52
|
+
const provider = isDefined(moduleOptions.vertex) ? vertexAI : googleAI;
|
|
53
|
+
return provider.model(...args);
|
|
54
|
+
}
|
|
55
|
+
const _injectModel = injectModel;
|
|
56
|
+
export { _injectModel as injectModel };
|
package/ai/index.d.ts
CHANGED
package/ai/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Json } from '../../types/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Formats objects and arrays for AI context. Requires values to be primitive types (or arrays of primitive types).
|
|
4
|
+
* Nesting of arrays is only supported one level deep and only recommended for a short list of items.
|
|
5
|
+
* If keys are not provided, all supported properties will be included. In case of arrays of objects, the keys of the first object will be used.
|
|
6
|
+
* @param data data to format
|
|
7
|
+
* @param dataTypeName name of the data type (e.g., "document", "users")
|
|
8
|
+
* @param keys keys to include in the output; can be property names or tuples of [property name, value extractor function]
|
|
9
|
+
* @returns formatted string representation of the data
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Format data as TOON string for AI context.
|
|
13
|
+
* @param data data to format
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatData(data: Json): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { encode } from '@toon-format/toon';
|
|
2
|
+
/**
|
|
3
|
+
* Formats objects and arrays for AI context. Requires values to be primitive types (or arrays of primitive types).
|
|
4
|
+
* Nesting of arrays is only supported one level deep and only recommended for a short list of items.
|
|
5
|
+
* If keys are not provided, all supported properties will be included. In case of arrays of objects, the keys of the first object will be used.
|
|
6
|
+
* @param data data to format
|
|
7
|
+
* @param dataTypeName name of the data type (e.g., "document", "users")
|
|
8
|
+
* @param keys keys to include in the output; can be property names or tuples of [property name, value extractor function]
|
|
9
|
+
* @returns formatted string representation of the data
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Format data as TOON string for AI context.
|
|
13
|
+
* @param data data to format
|
|
14
|
+
*/
|
|
15
|
+
export function formatData(data) {
|
|
16
|
+
return encode(data, { keyFolding: 'safe', indent: 2 });
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ListStyle = 'sections' | 'ordered' | 'unordered';
|
|
2
|
+
type InstructionsListContent = string[] | Instructions;
|
|
3
|
+
export type InstructionsList = {
|
|
4
|
+
style: ListStyle;
|
|
5
|
+
instruction?: string;
|
|
6
|
+
items: InstructionsListContent;
|
|
7
|
+
};
|
|
8
|
+
export type Instructions = {
|
|
9
|
+
[key: string]: string | string[] | InstructionsList | Instructions;
|
|
10
|
+
};
|
|
11
|
+
export declare function sections(items: InstructionsListContent): InstructionsList;
|
|
12
|
+
export declare function sections(instruction: string, items: InstructionsListContent): InstructionsList;
|
|
13
|
+
export declare function orderedList(items: InstructionsListContent): InstructionsList;
|
|
14
|
+
export declare function orderedList(instruction: string, items: InstructionsListContent): InstructionsList;
|
|
15
|
+
export declare function unorderedList(items: InstructionsListContent): InstructionsList;
|
|
16
|
+
export declare function unorderedList(instruction: string, items: InstructionsListContent): InstructionsList;
|
|
17
|
+
/**
|
|
18
|
+
* Formats instructions into a string representation suitable for AI prompts.
|
|
19
|
+
* @param node
|
|
20
|
+
* @param options
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatInstructions(node: Instructions | InstructionsList | string[], options?: {
|
|
23
|
+
initialDepth?: number;
|
|
24
|
+
}): string;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { hasOwnProperty, objectEntries } from '../../utils/object/object.js';
|
|
2
|
+
import { assertDefined, isArray, isDefined, isObject, isString } from '../../utils/type-guards.js';
|
|
3
|
+
// --- Factories ---
|
|
4
|
+
function list(style, instructionOrItems, itemsOrNothing) {
|
|
5
|
+
const instruction = isString(instructionOrItems) ? instructionOrItems : undefined;
|
|
6
|
+
const items = isString(instructionOrItems) ? itemsOrNothing : instructionOrItems;
|
|
7
|
+
assertDefined(items, 'Instructions list is empty.');
|
|
8
|
+
return { style, instruction, items };
|
|
9
|
+
}
|
|
10
|
+
export function sections(instructionOrItems, itemsOrNothing) {
|
|
11
|
+
return list('sections', instructionOrItems, itemsOrNothing);
|
|
12
|
+
}
|
|
13
|
+
export function orderedList(instructionOrItems, itemsOrNothing) {
|
|
14
|
+
return list('ordered', instructionOrItems, itemsOrNothing);
|
|
15
|
+
}
|
|
16
|
+
export function unorderedList(instructionOrItems, itemsOrNothing) {
|
|
17
|
+
return list('unordered', instructionOrItems, itemsOrNothing);
|
|
18
|
+
}
|
|
19
|
+
// --- Type Guards ---
|
|
20
|
+
function isInstructionsList(obj) {
|
|
21
|
+
return isObject(obj) && hasOwnProperty(obj, 'style') && hasOwnProperty(obj, 'items');
|
|
22
|
+
}
|
|
23
|
+
// --- Formatter Logic ---
|
|
24
|
+
const INDENT_SIZE = 2;
|
|
25
|
+
function getPrefix(style, index, sectionDepth) {
|
|
26
|
+
switch (style) {
|
|
27
|
+
case 'ordered':
|
|
28
|
+
return `${index + 1}. `;
|
|
29
|
+
case 'unordered':
|
|
30
|
+
return '- ';
|
|
31
|
+
case 'sections':
|
|
32
|
+
return '#'.repeat(Math.max(1, sectionDepth)) + ' ';
|
|
33
|
+
default:
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Formats a string that might span multiple lines.
|
|
39
|
+
* It calculates the hanging indent based on the length of the prefix used on the first line.
|
|
40
|
+
*/
|
|
41
|
+
function formatWithHangingIndent(text, baseIndent, prefix) {
|
|
42
|
+
const lines = text.split('\n');
|
|
43
|
+
if (lines.length == 0) {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
const firstLine = `${baseIndent}${prefix}${lines[0]}`;
|
|
47
|
+
if (lines.length == 1) {
|
|
48
|
+
return firstLine;
|
|
49
|
+
}
|
|
50
|
+
// Create a spacer that exactly matches the visual length of " 1. " or " - "
|
|
51
|
+
const hangingSpacer = ' '.repeat(baseIndent.length + prefix.length);
|
|
52
|
+
return [
|
|
53
|
+
firstLine,
|
|
54
|
+
...lines.slice(1).map((line) => `${hangingSpacer}${line}`),
|
|
55
|
+
].join('\n');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Main recursive formatter.
|
|
59
|
+
*/
|
|
60
|
+
function processNode(node, context) {
|
|
61
|
+
// 1. Unwrap InstructionsList (The Wrapper)
|
|
62
|
+
// If the node is a wrapper, we adopt its style and instruction, then process its items.
|
|
63
|
+
if (isInstructionsList(node)) {
|
|
64
|
+
// Note: We don't print the "instruction" here (e.g., "Use Markdown").
|
|
65
|
+
// If this Wrapper is a root node, the instruction is usually printed by the caller or ignored.
|
|
66
|
+
// If this Wrapper is a value of a key, the key printer handles the instruction.
|
|
67
|
+
// However, if we have a "Root Wrapper" with an instruction (rare in your example), handle it:
|
|
68
|
+
const header = node.instruction ? `${node.instruction}\n` : '';
|
|
69
|
+
// Determine next context
|
|
70
|
+
const nextContext = {
|
|
71
|
+
indentDepth: context.indentDepth, // Wrappers don't indent themselves, their content does
|
|
72
|
+
style: node.style,
|
|
73
|
+
sectionDepth: node.style == 'sections' ? context.sectionDepth : context.sectionDepth, // Section depth increments internally
|
|
74
|
+
};
|
|
75
|
+
return header + processNode(node.items, nextContext);
|
|
76
|
+
}
|
|
77
|
+
// Common Constants for this level
|
|
78
|
+
const isSection = context.style == 'sections';
|
|
79
|
+
const currentBaseIndent = ' '.repeat(isSection ? 0 : context.indentDepth * INDENT_SIZE);
|
|
80
|
+
const separator = isSection ? '\n\n' : '\n';
|
|
81
|
+
// 2. Handle Arrays (Simple Lists)
|
|
82
|
+
if (isArray(node)) {
|
|
83
|
+
return node.map((item, index) => {
|
|
84
|
+
const prefix = getPrefix(context.style, index, context.sectionDepth);
|
|
85
|
+
return formatWithHangingIndent(item, currentBaseIndent, prefix);
|
|
86
|
+
}).join(separator);
|
|
87
|
+
}
|
|
88
|
+
// 3. Handle Objects (Key-Value Maps)
|
|
89
|
+
return objectEntries(node).map(([key, value], index) => {
|
|
90
|
+
const prefix = getPrefix(context.style, index, context.sectionDepth);
|
|
91
|
+
// Detect if the Value is a Wrapper (e.g. `Key: ordered(...)`)
|
|
92
|
+
// This allows us to pull the wrapper's "instruction" up to the Key line.
|
|
93
|
+
const isValueWrapper = isInstructionsList(value);
|
|
94
|
+
const effectiveValue = isValueWrapper ? value.items : value;
|
|
95
|
+
const instruction = (isValueWrapper && isDefined(value.instruction)) ? ` ${value.instruction}` : '';
|
|
96
|
+
const childStyle = isValueWrapper ? value.style : (isSection ? 'unordered' : 'unordered');
|
|
97
|
+
// Formatting the Header Line (The Key)
|
|
98
|
+
let headerLine = '';
|
|
99
|
+
if (isSection) {
|
|
100
|
+
// Header format: "# Key" or "# Key\n\nInstruction"
|
|
101
|
+
const instructionPart = (instruction.length > 0) ? `\n\n${instruction.trim()}` : '';
|
|
102
|
+
headerLine = `${currentBaseIndent}${prefix}${key}${instructionPart}`;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// List format: "- **Key:**" or "- **Key:** Instruction"
|
|
106
|
+
const keyPart = `**${key}:**`;
|
|
107
|
+
headerLine = `${currentBaseIndent}${prefix}${keyPart}${instruction}`;
|
|
108
|
+
}
|
|
109
|
+
// Determine context for the children
|
|
110
|
+
// If we are a Section, children reset indent to 0.
|
|
111
|
+
// If we are a List, children indent + 1.
|
|
112
|
+
const nextIndentDepth = isSection ? 0 : context.indentDepth + 1;
|
|
113
|
+
// If the child acts as a section (Wrapper was `sections(...)`), increment H-level.
|
|
114
|
+
const nextSectionDepth = (isValueWrapper && value.style == 'sections')
|
|
115
|
+
? context.sectionDepth + 1
|
|
116
|
+
: context.sectionDepth;
|
|
117
|
+
// Recurse
|
|
118
|
+
// If the value is a simple string, we print it inline if possible, or block if it's long?
|
|
119
|
+
// Your requirement: Strings in objects are usually descriptions.
|
|
120
|
+
if (isString(effectiveValue)) {
|
|
121
|
+
// If it's a string, we treat it as content on the SAME line for lists (via hanging indent logic),
|
|
122
|
+
// or a new paragraph for Sections.
|
|
123
|
+
if (isSection) {
|
|
124
|
+
// Section: Header \n\n Content
|
|
125
|
+
return `${headerLine}\n\n${effectiveValue.trim()}`;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// List: "- **Key:** Value"
|
|
129
|
+
// We need to construct the full string to calculate hanging indent correctly.
|
|
130
|
+
// headerLine already contains indentation + prefix + key.
|
|
131
|
+
// We strip the indentation to feed it into the formatting helper effectively.
|
|
132
|
+
const fullLine = `${headerLine} ${effectiveValue}`.trim();
|
|
133
|
+
return formatWithHangingIndent(fullLine, currentBaseIndent, '');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// If Value is Object/Array/Wrapper
|
|
137
|
+
const body = processNode(effectiveValue, {
|
|
138
|
+
indentDepth: nextIndentDepth,
|
|
139
|
+
style: childStyle,
|
|
140
|
+
sectionDepth: nextSectionDepth,
|
|
141
|
+
});
|
|
142
|
+
const bodySeparator = isSection ? '\n\n' : '\n';
|
|
143
|
+
// Edge case: If it's a section, we constructed the header, now append body.
|
|
144
|
+
// If it's a list, the header line serves as the parent item.
|
|
145
|
+
return `${headerLine}${bodySeparator}${body}`;
|
|
146
|
+
}).join(separator);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Formats instructions into a string representation suitable for AI prompts.
|
|
150
|
+
* @param node
|
|
151
|
+
* @param options
|
|
152
|
+
*/
|
|
153
|
+
export function formatInstructions(node, options = {}) {
|
|
154
|
+
// Heuristic: If passing a raw object, assume it's a Root Section unless specified otherwise.
|
|
155
|
+
// If passing a Wrapper, the Wrapper dictates the style.
|
|
156
|
+
const initialStyle = isInstructionsList(node)
|
|
157
|
+
? node.style
|
|
158
|
+
: isArray(node)
|
|
159
|
+
? 'unordered'
|
|
160
|
+
: 'sections';
|
|
161
|
+
return processNode(node, {
|
|
162
|
+
indentDepth: options.initialDepth ?? 0,
|
|
163
|
+
sectionDepth: 1,
|
|
164
|
+
style: initialStyle,
|
|
165
|
+
}).trim();
|
|
166
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { unorderedList } from './instructions-formatter.js';
|
|
2
|
+
export const jsonOutputInstructions = {
|
|
3
|
+
'JSON Output': unorderedList({
|
|
4
|
+
'Schema Compliance': 'Generate valid JSON that strictly matches the provided schema.',
|
|
5
|
+
'Nullable fields with missing data': 'Must be set to literal `null`.',
|
|
6
|
+
'Optional fields with missing data': 'Omit the key entirely (sparse JSON).',
|
|
7
|
+
}),
|
|
8
|
+
};
|
|
@@ -29,6 +29,8 @@ export declare class DocumentFileService extends Transactional {
|
|
|
29
29
|
getContent(document: Document): Promise<Uint8Array>;
|
|
30
30
|
getContentStream(document: Document): ReadableStream<Uint8Array>;
|
|
31
31
|
getContentUrl(document: Document, download?: boolean): Promise<string>;
|
|
32
|
+
/** Gets the underlying object storage object for the document file */
|
|
33
|
+
getObject(document: Document): Promise<import("../../../object-storage/index.js").ObjectStorageObject>;
|
|
32
34
|
getPreview(document: Document, page?: number): Promise<Uint8Array>;
|
|
33
35
|
getPreviewStream(document: Document, page?: number): ReadableStream<Uint8Array>;
|
|
34
36
|
getPreviewUrl(document: Document, page?: number): Promise<string>;
|
|
@@ -56,8 +56,6 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
56
56
|
var e = new Error(message);
|
|
57
57
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
58
58
|
});
|
|
59
|
-
var _a;
|
|
60
|
-
var DocumentFileService_1;
|
|
61
59
|
import sharp, {} from 'sharp';
|
|
62
60
|
import { match } from 'ts-pattern';
|
|
63
61
|
import { AiService } from '../../../ai/ai.service.js';
|
|
@@ -66,7 +64,6 @@ import { NotImplementedError } from '../../../errors/not-implemented.error.js';
|
|
|
66
64
|
import { getMimeType, getMimeTypeExtensions, mimeTypes } from '../../../file/index.js';
|
|
67
65
|
import { TemporaryFile } from '../../../file/server/index.js';
|
|
68
66
|
import { inject } from '../../../injector/inject.js';
|
|
69
|
-
import { Logger } from '../../../logger/logger.js';
|
|
70
67
|
import { ObjectStorage } from '../../../object-storage/index.js';
|
|
71
68
|
import { Transactional } from '../../../orm/server/index.js';
|
|
72
69
|
import { pdfToImage } from '../../../pdf/index.js';
|
|
@@ -80,13 +77,12 @@ import { millisecondsPerMinute, secondsPerMinute } from '../../../utils/units.js
|
|
|
80
77
|
import { Document } from '../../models/index.js';
|
|
81
78
|
import { DocumentManagementConfiguration } from '../module.js';
|
|
82
79
|
import { DocumentManagementSingleton } from './singleton.js';
|
|
83
|
-
let DocumentFileService =
|
|
80
|
+
let DocumentFileService = class DocumentFileService extends Transactional {
|
|
84
81
|
#configuration = inject(DocumentManagementConfiguration);
|
|
85
82
|
#aiService = inject(AiService);
|
|
86
83
|
#fileObjectStorage = inject(ObjectStorage, this.#configuration.fileObjectStorageModule);
|
|
87
84
|
#filePreviewObjectStorage = inject(ObjectStorage, this.#configuration.filePreviewObjectStorageModule);
|
|
88
85
|
#fileUploadObjectStorage = inject(ObjectStorage, { module: this.#configuration.fileUploadObjectStorageModule, configuration: { lifecycle: { expiration: { after: 5 * secondsPerMinute } } } });
|
|
89
|
-
#logger = inject(Logger, DocumentFileService_1.name);
|
|
90
86
|
#aiFilePartCache = new Map();
|
|
91
87
|
/**
|
|
92
88
|
* Initiates a file upload
|
|
@@ -145,6 +141,11 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
|
|
|
145
141
|
async getContentUrl(document, download = false) {
|
|
146
142
|
return await this.getDocumentFileContentObjectUrl(document, document.title ?? document.id, download);
|
|
147
143
|
}
|
|
144
|
+
/** Gets the underlying object storage object for the document file */
|
|
145
|
+
async getObject(document) {
|
|
146
|
+
const objectKey = getObjectKey(document.id);
|
|
147
|
+
return await this.#fileObjectStorage.getObject(objectKey);
|
|
148
|
+
}
|
|
148
149
|
async getPreview(document, page = 1) {
|
|
149
150
|
const objectKey = getObjectKey(document.id);
|
|
150
151
|
await this.createPreviewIfNotExists(document, page);
|
|
@@ -197,12 +198,12 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
|
|
|
197
198
|
const content = await this.#fileObjectStorage.getContent(key);
|
|
198
199
|
const image = await match(document.mimeType)
|
|
199
200
|
.with('application/pdf', async () => {
|
|
200
|
-
const imageBytes = await pdfToImage(content, page, 768, '
|
|
201
|
+
const imageBytes = await pdfToImage(content, page, 768, 'png');
|
|
201
202
|
return await imageToPreview(imageBytes);
|
|
202
203
|
})
|
|
203
204
|
.with('image/*', async () => await imageToPreview(content))
|
|
204
205
|
.otherwise(() => { throw new NotImplementedError('Preview generation is not implemented for this file type.'); });
|
|
205
|
-
await this.#filePreviewObjectStorage.uploadObject(key, image, { contentLength: image.length, contentType: 'image/
|
|
206
|
+
await this.#filePreviewObjectStorage.uploadObject(key, image, { contentLength: image.length, contentType: 'image/webp' });
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
async getDocumentFileContentObjectUrl(document, title, download) {
|
|
@@ -216,7 +217,7 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
|
|
|
216
217
|
});
|
|
217
218
|
}
|
|
218
219
|
};
|
|
219
|
-
DocumentFileService =
|
|
220
|
+
DocumentFileService = __decorate([
|
|
220
221
|
DocumentManagementSingleton()
|
|
221
222
|
], DocumentFileService);
|
|
222
223
|
export { DocumentFileService };
|
|
@@ -233,6 +234,6 @@ async function imageToPreview(input) {
|
|
|
233
234
|
withoutEnlargement: true,
|
|
234
235
|
fastShrinkOnLoad: false,
|
|
235
236
|
})
|
|
236
|
-
.toFormat('
|
|
237
|
+
.toFormat('webp', { quality: 75 })
|
|
237
238
|
.toBuffer();
|
|
238
239
|
}
|
|
@@ -15,6 +15,7 @@ export type DocumentInformationExtractionResult = {
|
|
|
15
15
|
};
|
|
16
16
|
export declare class DocumentManagementAiService {
|
|
17
17
|
#private;
|
|
18
|
+
extractDocumentContent(tenantId: string, documentId: string): Promise<string>;
|
|
18
19
|
classifyDocumentType(tenantId: string, documentId: string): Promise<string>;
|
|
19
20
|
extractDocumentInformation(tenantId: string, documentId: string): Promise<DocumentInformationExtractionResult>;
|
|
20
21
|
findSuitableCollectionsForDocument(document: Document, collectionIds: string[]): Promise<string[]>;
|