@xpert-ai/plugin-rag-vlm 0.0.1

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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # rag-vlm
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build rag-vlm` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test rag-vlm` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,6 @@
1
+ import type { XpertPlugin } from '@xpert-ai/plugin-sdk';
2
+ import { z } from 'zod';
3
+ declare const ConfigSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
4
+ declare const plugin: XpertPlugin<z.infer<typeof ConfigSchema>>;
5
+ export default plugin;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,QAAA,MAAM,YAAY,gDAChB,CAAC;AAEH,QAAA,MAAM,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CA2BrD,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ import { readFileSync } from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ import { dirname, join } from 'path';
4
+ import { z } from 'zod';
5
+ import { VlmDefaultPlugin } from './lib/vlm.module.js';
6
+ import { SvgIcon } from './lib/types.js';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
10
+ const ConfigSchema = z.object({});
11
+ const plugin = {
12
+ meta: {
13
+ name: packageJson.name,
14
+ version: packageJson.version,
15
+ category: 'vlm',
16
+ icon: {
17
+ type: 'svg',
18
+ value: SvgIcon
19
+ },
20
+ displayName: 'VLM Default',
21
+ description: 'Provide VLM functionality using default settings',
22
+ keywords: ['pdf', 'markdown', 'json', 'vlm', 'default'],
23
+ author: 'XpertAI Team',
24
+ },
25
+ config: {
26
+ schema: ConfigSchema,
27
+ },
28
+ register(ctx) {
29
+ ctx.logger.log('register VLM default plugin');
30
+ return { module: VlmDefaultPlugin, global: true };
31
+ },
32
+ async onStart(ctx) {
33
+ ctx.logger.log('vlm default plugin started');
34
+ },
35
+ async onStop(ctx) {
36
+ ctx.logger.log('vlm default plugin stopped');
37
+ },
38
+ };
39
+ export default plugin;
@@ -0,0 +1,3 @@
1
+ export declare const VlmDefault = "vlm-default";
2
+ export declare const SvgIcon = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\t viewBox=\"0 0 960 960\" style=\"enable-background:new 0 0 960 960;\" xml:space=\"preserve\">\n<style type=\"text/css\">\n\t.st0{fill:#135468;}\n\t.st1{fill:#FFFFFF;}\n\t.st2{fill:#6DBCDB;}\n\t.st3{fill:#333333;}\n\t.st4{fill:none;stroke:#FFFFFF;stroke-width:22.1618;stroke-linecap:round;stroke-miterlimit:10;}\n</style>\n<g>\n\t<circle class=\"st0\" cx=\"480\" cy=\"480\" r=\"300.9\"/>\n\t<path class=\"st1\" d=\"M750.4,480c0,0-121.1,130-270.4,130S209.6,480,209.6,480S330.7,350,480,350S750.4,480,750.4,480z\"/>\n\t<path class=\"st1\" d=\"M750.4,480c0,0-121.1,130-270.4,130S209.6,480,209.6,480S330.7,350,480,350S750.4,480,750.4,480z\"/>\n\t<circle class=\"st2\" cx=\"480\" cy=\"478.4\" r=\"102.8\"/>\n\t<circle class=\"st3\" cx=\"480\" cy=\"478.4\" r=\"58.6\"/>\n\t<circle class=\"st1\" cx=\"441.2\" cy=\"444.1\" r=\"24.3\"/>\n\t<line class=\"st4\" x1=\"363.1\" y1=\"323.7\" x2=\"328.1\" y2=\"286.8\"/>\n\t<line class=\"st4\" x1=\"631.9\" y1=\"286.8\" x2=\"596.9\" y2=\"323.7\"/>\n\t<line class=\"st4\" x1=\"482.7\" y1=\"300.9\" x2=\"482.7\" y2=\"256.8\"/>\n</g>\n</svg>\n";
3
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,gBAAgB,CAAA;AAEvC,eAAO,MAAM,OAAO,8uCAsBnB,CAAA"}
@@ -0,0 +1,24 @@
1
+ export const VlmDefault = 'vlm-default';
2
+ export const SvgIcon = `<?xml version="1.0" encoding="utf-8"?>
3
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
+ viewBox="0 0 960 960" style="enable-background:new 0 0 960 960;" xml:space="preserve">
5
+ <style type="text/css">
6
+ .st0{fill:#135468;}
7
+ .st1{fill:#FFFFFF;}
8
+ .st2{fill:#6DBCDB;}
9
+ .st3{fill:#333333;}
10
+ .st4{fill:none;stroke:#FFFFFF;stroke-width:22.1618;stroke-linecap:round;stroke-miterlimit:10;}
11
+ </style>
12
+ <g>
13
+ <circle class="st0" cx="480" cy="480" r="300.9"/>
14
+ <path class="st1" d="M750.4,480c0,0-121.1,130-270.4,130S209.6,480,209.6,480S330.7,350,480,350S750.4,480,750.4,480z"/>
15
+ <path class="st1" d="M750.4,480c0,0-121.1,130-270.4,130S209.6,480,209.6,480S330.7,350,480,350S750.4,480,750.4,480z"/>
16
+ <circle class="st2" cx="480" cy="478.4" r="102.8"/>
17
+ <circle class="st3" cx="480" cy="478.4" r="58.6"/>
18
+ <circle class="st1" cx="441.2" cy="444.1" r="24.3"/>
19
+ <line class="st4" x1="363.1" y1="323.7" x2="328.1" y2="286.8"/>
20
+ <line class="st4" x1="631.9" y1="286.8" x2="596.9" y2="323.7"/>
21
+ <line class="st4" x1="482.7" y1="300.9" x2="482.7" y2="256.8"/>
22
+ </g>
23
+ </svg>
24
+ `;
@@ -0,0 +1,13 @@
1
+ import { IOnPluginBootstrap, IOnPluginDestroy } from '@xpert-ai/plugin-sdk';
2
+ export declare class VlmDefaultPlugin implements IOnPluginBootstrap, IOnPluginDestroy {
3
+ private logEnabled;
4
+ /**
5
+ * Called when the plugin is being initialized.
6
+ */
7
+ onPluginBootstrap(): void | Promise<void>;
8
+ /**
9
+ * Called when the plugin is being destroyed.
10
+ */
11
+ onPluginDestroy(): void | Promise<void>;
12
+ }
13
+ //# sourceMappingURL=vlm.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vlm.module.d.ts","sourceRoot":"","sources":["../../src/lib/vlm.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAK/F,qBAea,gBAAiB,YAAW,kBAAkB,EAAE,gBAAgB;IAE5E,OAAO,CAAC,UAAU,CAAQ;IAE1B;;OAEG;IACH,iBAAiB,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC;;OAEG;IACH,eAAe,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAKvC"}
@@ -0,0 +1,45 @@
1
+ var VlmDefaultPlugin_1;
2
+ import { __decorate } from "tslib";
3
+ import { XpertServerPlugin } from '@xpert-ai/plugin-sdk';
4
+ import { ConfigModule } from '@nestjs/config';
5
+ import chalk from 'chalk';
6
+ import { VlmDefaultStrategy } from './vlm.strategy.js';
7
+ let VlmDefaultPlugin = VlmDefaultPlugin_1 = class VlmDefaultPlugin {
8
+ constructor() {
9
+ // We disable by default additional logging for each event to avoid cluttering the logs
10
+ this.logEnabled = true;
11
+ }
12
+ /**
13
+ * Called when the plugin is being initialized.
14
+ */
15
+ onPluginBootstrap() {
16
+ if (this.logEnabled) {
17
+ console.log(chalk.green(`${VlmDefaultPlugin_1.name} is being bootstrapped...`));
18
+ }
19
+ }
20
+ /**
21
+ * Called when the plugin is being destroyed.
22
+ */
23
+ onPluginDestroy() {
24
+ if (this.logEnabled) {
25
+ console.log(chalk.green(`${VlmDefaultPlugin_1.name} is being destroyed...`));
26
+ }
27
+ }
28
+ };
29
+ VlmDefaultPlugin = VlmDefaultPlugin_1 = __decorate([
30
+ XpertServerPlugin({
31
+ /**
32
+ * An array of modules that will be imported and registered with the plugin.
33
+ */
34
+ imports: [ConfigModule],
35
+ /**
36
+ * An array of Entity classes. The plugin (or ORM) will
37
+ * register these entities for use within the application.
38
+ */
39
+ entities: [],
40
+ providers: [
41
+ VlmDefaultStrategy,
42
+ ]
43
+ })
44
+ ], VlmDefaultPlugin);
45
+ export { VlmDefaultPlugin };
@@ -0,0 +1,29 @@
1
+ import { ChunkMetadata, FileSystemPermission, IImageUnderstandingStrategy, LLMPermission, TImageUnderstandingConfig, TImageUnderstandingResult } from '@xpert-ai/plugin-sdk';
2
+ import { IconType, IKnowledgeDocument } from '@metad/contracts';
3
+ export declare class VlmDefaultStrategy implements IImageUnderstandingStrategy {
4
+ readonly permissions: (FileSystemPermission | LLMPermission)[];
5
+ readonly meta: {
6
+ name: string;
7
+ label: {
8
+ en_US: string;
9
+ zh_Hans: string;
10
+ };
11
+ description: {
12
+ en_US: string;
13
+ zh_Hans: string;
14
+ };
15
+ configSchema: {
16
+ type: string;
17
+ properties: {};
18
+ };
19
+ icon: {
20
+ type: IconType;
21
+ value: string;
22
+ color: string;
23
+ };
24
+ };
25
+ validateConfig(config: TImageUnderstandingConfig): Promise<void>;
26
+ understandImages(doc: IKnowledgeDocument<ChunkMetadata>, config: TImageUnderstandingConfig): Promise<TImageUnderstandingResult>;
27
+ private runV;
28
+ }
29
+ //# sourceMappingURL=vlm.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vlm.strategy.d.ts","sourceRoot":"","sources":["../../src/lib/vlm.strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,2BAA2B,EAE3B,aAAa,EACb,yBAAyB,EACzB,yBAAyB,EAC1B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAqC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AASlG,qBAEa,kBAAmB,YAAW,2BAA2B;IACpE,QAAQ,CAAC,WAAW,2CAUnB;IAED,QAAQ,CAAC,IAAI;;;;;;;;;;;;;;;kBAYM,QAAQ;;;;MAI1B;IAEK,cAAc,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhE,gBAAgB,CACpB,GAAG,EAAE,kBAAkB,CAAC,aAAa,CAAC,EACtC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,yBAAyB,CAAC;YAoDvB,IAAI;CA4BnB"}
@@ -0,0 +1,121 @@
1
+ import { __decorate } from "tslib";
2
+ import { Injectable } from '@nestjs/common';
3
+ import { ImageUnderstandingStrategy } from '@xpert-ai/plugin-sdk';
4
+ import { buildChunkTree, collectTreeLeaves } from '@metad/contracts';
5
+ import { Document } from '@langchain/core/documents';
6
+ import sharp from 'sharp';
7
+ import { v4 as uuid } from 'uuid';
8
+ import { SvgIcon, VlmDefault } from './types.js';
9
+ // Regex for markdown image tag: ![](image.png) or ![alt](image.png)
10
+ const IMAGE_REGEX = /!\[[^\]]*\]\s*\(((?:https?:\/\/[^)]+|[^)\s]+))(\s*"[^"]*")?\)/g;
11
+ let VlmDefaultStrategy = class VlmDefaultStrategy {
12
+ constructor() {
13
+ this.permissions = [
14
+ {
15
+ type: 'filesystem',
16
+ operations: ['read'],
17
+ scope: []
18
+ },
19
+ {
20
+ type: 'llm',
21
+ capability: 'vision',
22
+ }
23
+ ];
24
+ this.meta = {
25
+ name: VlmDefault,
26
+ label: { en_US: 'VLM', zh_Hans: '视觉语言模型' },
27
+ description: {
28
+ en_US: 'Use V(ision)LM to understand images, the knowledge base needs to be configured with a visual model.',
29
+ zh_Hans: '使用视觉大模型来理解图片,知识库需要配置视觉模型。'
30
+ },
31
+ configSchema: {
32
+ type: 'object',
33
+ properties: {}
34
+ },
35
+ icon: {
36
+ type: 'svg',
37
+ value: SvgIcon,
38
+ color: '#2d8cf0'
39
+ }
40
+ };
41
+ }
42
+ async validateConfig(config) {
43
+ if (!config?.visionModel) {
44
+ throw new Error('Vision Model is required');
45
+ }
46
+ }
47
+ async understandImages(doc, config) {
48
+ await this.validateConfig(config);
49
+ const client = config.visionModel; // ✅ Injected by the core system
50
+ const params = {
51
+ files: doc.metadata?.assets?.filter((asset) => asset.type === 'image'),
52
+ chunks: doc.chunks
53
+ };
54
+ const tree = buildChunkTree(doc.chunks);
55
+ const leaves = collectTreeLeaves(tree);
56
+ const chunks = [];
57
+ // const pages : Document<Partial<ChunkMetadata>>[] = []
58
+ for await (const chunk of leaves) {
59
+ const assets = [];
60
+ chunk.metadata['chunkId'] ??= uuid();
61
+ // Source Document Block
62
+ chunks.push(chunk);
63
+ // Find image tags inside the chunk
64
+ const matches = Array.from(chunk.pageContent.matchAll(IMAGE_REGEX));
65
+ for (const match of matches) {
66
+ const url = match[1]; // image-url.png
67
+ const asset = params.files.find((a) => a.url === url);
68
+ if (asset && !assets.some((_) => _ === asset.url)) {
69
+ const description = await this.runV(client, chunk.pageContent, asset.filePath, config);
70
+ assets.push(asset.url);
71
+ chunks.push(new Document({
72
+ pageContent: description,
73
+ metadata: {
74
+ mediaType: 'image',
75
+ chunkId: `img-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
76
+ parentId: chunk.metadata['chunkId'],
77
+ imagePath: asset.filePath,
78
+ // source: asset.filename,
79
+ parser: 'vlm'
80
+ }
81
+ }));
82
+ }
83
+ }
84
+ }
85
+ return {
86
+ chunks,
87
+ metadata: {}
88
+ };
89
+ }
90
+ async runV(client, context, imagePath, config) {
91
+ const imageStr = await config.permissions.fileSystem.readFile(imagePath);
92
+ const sharped = sharp(imageStr);
93
+ const imageData = await sharped.resize(1024).toBuffer();
94
+ const fileInfo = await sharped.metadata();
95
+ const mimetype = fileInfo.format ? `image/${fileInfo.format}` : 'image/png';
96
+ const response = await client.invoke([
97
+ {
98
+ role: 'system',
99
+ content: 'You are a professional assistant, helping people understand images in context. Please provide a narrative description of the image.'
100
+ },
101
+ {
102
+ role: 'user',
103
+ content: [
104
+ // { type: 'text', text: context },
105
+ {
106
+ type: 'image_url',
107
+ image_url: {
108
+ url: `data:${mimetype};base64,${imageData.toString('base64')}`
109
+ }
110
+ }
111
+ ]
112
+ }
113
+ ]);
114
+ return response.content;
115
+ }
116
+ };
117
+ VlmDefaultStrategy = __decorate([
118
+ Injectable(),
119
+ ImageUnderstandingStrategy(VlmDefault)
120
+ ], VlmDefaultStrategy);
121
+ export { VlmDefaultStrategy };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@xpert-ai/plugin-rag-vlm",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "@xpert-plugins-starter/source": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "!**/*.tsbuildinfo"
20
+ ],
21
+ "dependencies": {
22
+ "sharp": "0.33.5",
23
+ "tslib": "^2.3.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@xpert-ai/plugin-sdk": "^3.6.0",
27
+ "zod": "3.25.67",
28
+ "@nestjs/config": "^4.0.2",
29
+ "chalk": "4.1.2",
30
+ "@langchain/core": "0.3.72",
31
+ "@nestjs/common": "^11.1.6",
32
+ "@metad/contracts": "^3.6.0",
33
+ "uuid": "8.3.2"
34
+ }
35
+ }